#!/usr/local/bin/perl
##############################################################################
# COPYRIGHT NOTICE                                                           #
# Copyright (c) 1998,1999 Ira L. Gershenhorn.  All Rights Reserved.          #
#                                                                            #
# mgFargo may be used and modified free of charge by anyone so long as       #
# this copyright notice and the comments above remain intact.  By using this #
# code you agree to indemnify Ira L. Gershenhorn from any liability that     #  
# might arise from it's use.                                                 #  
#                                                                            #
# Selling the code for this program without prior written consent is         #
# expressly forbidden.  In other words, please ask first before you try and  #
# make money off of my program.                                              #
#                                                                            #
# Obtain permission before redistributing this software over the Internet or #
# in any other medium.	In all cases copyright and header must remain intact.#
#                                                                            # 
# mgFargo is free software; you can redistribute it and/or modify it		 #
# under the terms of the GNU General Public License as published by the		 #
# Free Software Foundation; either version 2 of the License, or (at			 #
# your option) any later version.											 #
#																			 #
# mgFargo is distributed in the hope that it will be useful, but			 #
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY #
# or FITNESS FOR A PARTICULAR PURPOSE.&nbsp; See the GNU General Public      #
# License for more details.                                                  #
#																			 #
# You should have received a copy of the GNU General Public License			 #
# along with this program; if not, write to the Free Software				 #
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #
##############################################################################
# Debug Commands
# perl mgFargo.pl -d ~/gen/files.i -p ~/gen/frprglist.txt -n -v  ~/gen/FR.app
# perl mgFargo-2.pl -d faf -p fap -n -v v71.i

=head1 NAME

B<mgFargo.pl> - Translate Magic PC v5.xx-v8.xx exported internal format files to a more readable and searchable format.

=head2 Features

=over 4

=item * Identifies and distinguishes multiple instances of fields.  

=item * Allows user-customized real field suffix definition.(LNKREF=suffix)
		Implemented if the remark field preceding any use of Real fields contains  "LNKREF=blah", 
		then a real field may be rendered "filename.blah_fieldname"

=item * Prepends file names to real fields.

=item * Reads an ini (mgFargo.ini) to obviate setting command line parameters.

=item * Facilitates change management.

=item * Enables the use of configuration management tools.

=back 

=head1 SYNOPSIS

C<mgFargo [-hvnuf] [-s N] [-e N] [-p progist] [-d InternalFileExport] InternalProgramExport>

C<InternalProgramExport     output of Magic in internal format.>

For Detailed Help type: mgFargo -h

=head1 ARGUMENTS

=over

=item C<-p progList>

Unnecessary if you are using an application export.
Optional if you are converting one program and don't care that
none of the called programs are identified.  The lines in the
list have the same format as the Magic Document Export of
Programs Table of Contents.  Alternatively, it only requires
lines of the format:

       Program Name dd/dd dd:dd

There can be any text after the dd/dd and before the dd:dd or
after the dd:dd, where 'd' is a digit (0-9).  Formfeed
characters starting off lines will not be considered part of
the program name.

=item C<-d InternalFileExport>

Unnecessary if you are using an application export.
Optional if you are converting one program and don't care that
none of the real fields are identified.

=item C<-s>

Range Start.  For reporting on part of an application export.

=item C<-e>

Range End.    For reporting on part of an application export.

=item C<-v>

Verbose mode.  Gives progress report.

=item C<-f>

Indicates to use database file name prefixes for real fields.  The default
is not to use them.

=item C<-u>

Indicates to 'uniquify' variable names.  Default is to 'uniquify'.

=item C<-n>

Number the output files.

=item C<-m>

Get this manual page.

=item C<Alternative to command parameters>

In the same directory as the internal program export file, create an
B<mgFargo.ini> file having lines such as these:

   Verbose            = [0|1]
   numberFiles        = [0|1]
   uniquifyVars       = [0|1]
   useDfNamePrefixes  = [0|1]
   startProgram       = 999
   endProgram         = 999
   proglist           = FileSpec
   internalFileExport = FileSpec

   enableDefaults = True                ;enables the indicated defaults section
   defaultsSection = stdDefaults        ;indicates the defaults to be used when enabledDefaults=True

   [stdDefaults]
   defTaskType = Online                 ;not all defaults are shown here.
   defTaskMode = Modify                 ;a sample mgFargo.ini will show all defaults.

These properties correspond to the options v, n, u, f, s, e, p, and d
respectively.  The properties must begin in the first column.  A semi-colon
in front of any line disables or comments the line.

For logically valued fields, the value of '1' enables the property
and '0' disables.  Other fields take numeric or text arguments.

=back

=head1 EXAMPLES

=over

=item C<Sample call to convert an entire application using mgFargo.ini>

mgFargo /FACT/FACTRUN/FAP

=item C<Sample call to convert an entire application not using mgFargo.ini>

mgFargo -v -n -u -f /FACT/FACTRUN/FAP

=back 

=head1 Building an EXE

 perl2exe -perloptions=none \\ira\e\inetpub\iragershenhorn.home.att.net\download\mgFargo-0578.pl c:\perl509\bin\perlglob.exe

=head1 BUGS

 reported Nov 3, 1999:  dropped the function name 'STR' in expressions. see expandedExpression function.
 reported Oct 1, 1999:  doesn't report on change levels that are empty.
 insists on pulling files from somewhere when using application. maybe fixed.
 glob seems broken for NT, so we need full, not relative, pathnames.
 whether glob is broken or not, perl/bin must be in path or else the instances of glob use cause "bad command or filename" errors.
 glob now fails on AIX.
 Fails when application has no data files defined.  Looks for external data dictionary. Workaround: Create empty file.

=head2 Planned Enhancements

 code output merge functionality in mgFargo.
 keep it from putting spaces before and after the point in a number like "0.02".
 Expand defaults to have online and batch default sets.
 verify expression needs stop or warning. put error, put warning.
 Defaults exclusion option- have one switch enable disable and section to use.-read user defaults in mgFargo.ini.  Not include task and flow parameters that are defaults.
 Specify the Magic.ini to be used in the mgFargo.ini file or on the command line.
 Clean up formatting of display blocks.
 When looking for brackets, strip record first of all strings.
 Add documenting of Reports - currently skipping RPR=\{ records.
 Gotcha in FS 117 Debug LPR (LineView)
 Read MAGIC.INI to get '.eng' files. Allow it to be passed in on command line.
 Read .eng files for translation of Actions and Keyboard codes. Allow these to be passed in also.
 Read types fields . Allow passing in.
 Add GNU License or Shareware license text.

=head1 SUPPORT

Ira Gershenhorn E<lt>iragershenhorn@csi.comE<gt>

=head1 HISTORY

 09/18/98 Created from Epsilon reformatter
 10/02/98 Added support for incremental update mode.
 10/05/98 Bypass glob if it returns null.  On NT it seems to be broken. 
          Maybe I am missing a command line parameter. Whatever?
 10/05/98 Delete '=' signs following close paren in regexes. Worked in Unix, Not in NT.
 10/14/98 Added uniquify and datafile name prepending.
 10/15/98 Added pod suitable for text,html or manpage output.
 10/20/98 Force mgFargo.ini to start at first column. 
	      Fixed bug reading call_tsk args from version 6.00+.
	      Handle UDPs, Fix Put Warning.
          Stop writing blank lines for END_BLOCK and END_LNK.
	      Ignore Flow control in Prefix/Suffixes.
	      Don't print flow control items when they are the default.
          Add prefix 'Evaluate:' to all evaluates.
          Also present the return values of evaluates and exits.
          Present wait and show/hide for exits.
 12/08/98 051 fix problem with Exit to: not supporting Version 8.
 12/09/98 052 fix problem with not pulling expression with embedded double quotes.
 04/27/99 054 fix missing blocks, extra line after block conditional, missing program calls.
 07/13/99 055 fix blank programs/tasks
 07/14/99 056 capture sort segments
 07/19/99 057 special treatment of Range/Locate
 09/19/99 0572 expand filenumber to 4 digits for greater than 999. Really so they sort better in a directory.
 09/28/99 0573 expand long expression width to 1200 from 159 in FORM_DETAIL_L
 10/08/99 0573 use call prog or task string next to program or task description in event listing so it shows up in greps for 'call prog:'
 10/12/99 0574 fix uniquify and dictname prepend, moved timing of setting/getting options.  conditionally use certain perl extensions so people can work with just the standard installation
 10/12/99 0574 Increase width of events program or task to avoid truncation, and left justify the string.
 10/13/99 0575 Disable use POD
 10/15/99 0576 End erroneous truncation of field text where the text contained a pair of double quotes.
 10/18/99 0577 Allow Options: just printed 'allowOptions' instead of 'Yes' or 'No'.
 10/19/99 0578 Changed the cutoff for handling call prog/task parameters from 6.00 to 8.00. I wasn't sure with which magic version the format changed.  I had assumed 5->6 but I was wrong.
               For example, prior to this fix, version 7 users would not have seen any calls with parameters.
 10/28/99 0580 Restored use of Pod::Parser and Pod::Parser for perl2exe version.  Built with ActiveState Perl 5.005_03 build 519
 11/12/99 0581 Task Force Record Suffix was not showing expanded expressions, just the expression number.
			   A new mgFargo.ini was released to support one variable name change.
			   Added creation of mgapp-index.html which contains a simple index to the .ezr files created.
 05/22/00 0583 Insert a line consisting of a non-text funny character (a Control-A, octal 001) in line above 'Task Name:' so that it can be used
			limit regex searches.
 09/25/00 0584 Use .html extension and surround text in basic html tags if flag in mgFargo.ini is set.
	       Remove '.' after file number in "Main File:".

 11/02/00 0585 Some Forms were unnamed. NAME of a Form may not directly follow the brace, allow for some space in between.
		       Expressions for key of main file were not being calculated or printed.
 11/03/00 0586 Convert any 'xx'var references to @references as is done in task/program calls.
 11/13/00 0587 Report Return actions (PB_ACT = Pushbutton?).
			   Entire DIT_INFO section was not pulling in fields,
			   Now reads act_usr.eng to decode user actions and keys in Events and pushbutton return actions.  
 11/24/00 0588 Update to work with magic mgFargo wizard.
 11/24/00 0589 Update to work with Perl2exe.
 03/13/01 0600 Fixes many 8.3 issues.  This is a major revision.
		Display the main task as it # appears in Magic, not the file version with lots of dashes.
		Show form names in the layout section.
		Read the font table. Expand font numbers.
		Add dot notation Task level info in Task hierarchy.
		Have option to put item row/columns in forms first.
 04/15/01 0601 Now report DB Cache value.
 05/17/01 0602 Enable characters after Z for variable codes
 05/17/01 0603 Restore printing of static text in 5.xx forms.  Lost it with first 6xx version.
 10/26/01 0604 Expand virtual display area to 32 from 21 after seeing trunncation
 08/27/02 0605 Change name to mgFargo.  Update the popup menu and the pulldown menu for v8.
 07/11/04 0606 ??
 07/11/04 0606.01 Display virtuals in tab separated format additionally to current display.
 07/11/04 0606.02 Attempt to retain spaces in filenames didn't work, and would confuse Epsilon even if successful.
 07/13/04 0607 knock off leading tab, add trailing tab and label for Notes added in Word.  Would like to have notes appear here but can't.
	       Would need a remark  in Magic preceding the virtual that would be stored/printed with virtual.
 07/20/04 0609 Add HTML Merge.  see Form-comparisons.c which shows samples of merge and standard gui forms.

=head1 AUTHOR

Ira Gershenhorn E<lt>iragershenhorn@mindspring.comE<gt>

=cut

use IO;     #589
use IO::Pipe;
use IO::Socket;
use IO::Seekable;
use IO::File;
use IO::Handle;
#use IO::Dir;#604  This line must be commented for the .pl script version and uncommented for the EXE version.
use File::DosGlob 'glob';
use Pod::Usage;
use Pod::Parser;

my $pb_action;#587
my $start1 = time;
my $start2;

my $ddloaded = 0;

my $compatibilityMode = 0;
my $mgMajorVers = 0;
my $mgMinorVers = 609;
my $versionDate = "07/20/2004";
my $copyrightLine = "mgFargo V$mgMajorVers.$mgMinorVers Copyright (c) 1998-2001 Ira L. Gershenhorn & Co., Inc.";
#the following uses are only here for Perl2exe.  It doesn't know dependencies.
my $generatingVB = 0;
use vars qw($opt_i $opt_h $opt_n $opt_s $opt_e $opt_p $opt_d $opt_f $opt_u $opt_m $opt_x);
use Getopt::Std;

getopts( 'i:vnp:d:he:s:fumx' );
if (!$opt_i){ $opt_i = 'mgFargo.ini'}; #588 filespec for mgFargo.ini configuration file
if ($opt_h){  detailedUsage(); }
if ($opt_m){  manpage(); }

if( $opt_x ) {
	use IO;
	use IO::Seekable;
	use IO::File;
	use IO::Handle;
	use Pod::Usage;
	use Pod::Parser;
}


#Getopt::Long::Configure('bundling');
#GetOptions('verbose|v' => \$verbose,
#		  'trace' => \$trace,
#		  'help|?|h' => \$help,
#		  'manual' =>  \$manual,
#		   'debug' => \$debug,
#		   'numberfiles|n' => \$numberfiles,
#		   'programdict|p' => \$programdict,
#		   'filedict|d' => \$filedict,
#		   'uniquify|u' => \$uniquify,
#		   'start|s' => \$start,
#		   'end|e' => \$end)
#  or pod2usage(2);


my $os = $ENV{OS};
my $ddPrefixSeparator = '.';

if( ! -f $ARGV[0] ){ $error = "main input file \"$ARGV[0]\" does not exist"; usage();}

my $lnkref = '';
my $rangeDir;
my $locateDir;
my $dbfile;
my $dbaccess;
my $dbshare;
my $dbopen;
my $dbcachesize;
my $fld;
my $pic;
my $strg;
my $attr;
my $siz;
my $mdfy;
my $trns;
my $def;
my $mod;
my $ctrl;
my $null;
my $selectionTask;
my $cnf;
my $sloc;
my $sfail;
my $lstrg;
my $forceRecordSuffix;
my $updateDate;
my $updateTime;
my $progName;
my $outfile;
my $indentLevel;
my $indentExp = 'Y';
my $indentLevelPrev;
my @indentExp;
my $mergeString;

##default property values
#my $defTaskType = 'Online';
#my $defTaskMode = 'Modify';

#my $defSelectionTask	= 'No';
#my $defIsResident	= 'No';
#my $defOpenTaskWindow	= 'Yes';
#my $defCloseTaskWindow	= 'Yes';
#my $defForegroundWindow	= 'Yes';
#my $defRefreshWindow	= 'No';

#my $defFormRecords = 0;
#my $defFlip	= 'Yes';#??
#my $defAllowCycleRecordMain	= 'Yes';
#my $defConfirmUpdate	= 'No';
#my $defLocateExp	= '0';
#my $defLocateDir	= 'Ascending';

#my $defRangeExp	= '0';
#my $defRangeDir	= 'Ascending';
#my $defTaskEndTaskCondition	= 'No';
#my $defTaskEndCheck	= 'Before entering record';
#my $defSufix	= 'No';
#my $defTaskForceRecordDelete	= 'No';
#my $defAbort = 

#my $defLstrg	= 'On Modify';
#my $defSloc	    = 'Yes';
#my $defSfail	= 'Yes';

##Options Control

#my $defAllowOptions	= 'Yes';
#my $defAllowModify	= 'Yes';
#my $defAllowCreate	= 'Yes';
#my $defAllowDelete	= 'Yes';
#my $defAllowQuery	= 'Yes';
#my $defAllowLocate	= 'Yes';
#my $defAllowRange	= 'Yes';
#my $defAllowKeyChange	= 'Yes';
#my $defAllowSorting	= 'Yes';
#my $defAllowIOFiles	= 'Yes';
#my $defAllowAbort	= 'Yes';
#my $defAllowKeyOpt	= 'Yes';
#my $defAllowLocateInQuery	= 'Yes';
#my $defAllowReports	= 'No';

#my $defQueryRight	= 'None';
#my $defModifyRight	= 'None';
#my $defDeleteRight	= 'None';
#my $defExecuteRight	= 'None';

#my $defFlowSpeed     ='Combined';
#my $defFlowDirection ='Forward';

my $enableDefaults = 0;
my $defaultsSection = 'stdDefaults'; 

#some lookup tables
$flowMode{S} = 'Step';
$flowMode{F} = 'Fast';
$flowMode{C} = 'Combined';
$flowMode{B} = 'on Zoom (Before)';
$flowMode{Z} = 'on Zoom (Before)';#version 8
$flowMode{A} = 'on Zoom (After)';
$flowMode{J} = 'on Zoom (After)';#version 8
$flowDir{F} = 'forward';
$flowDir{C} = 'forward,back';
$flowDir{B} = 'backwards';

$initialTaskMode{M} ='Modify';#verified
$initialTaskMode{C} ='Create';#verified
$initialTaskMode{D} ='Delete'; #verified
$initialTaskMode{E} ='Query';#verified
$initialTaskMode{P} ='As Parent';#verified
$initialTaskMode{L} ='Locate';
$initialTaskMode{R} ='Range';
$initialTaskMode{K} ='Key';
$initialTaskMode{S} ='Sort';
$initialTaskMode{O} ='Files'; #verified
#$initialTaskMode{N} ='Options';#verified

#tab string

$tabstr = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
$spacestr = "                                                                                                                                               ";

print STDOUT "...loading dictionary\n" if $opt_v;

my $file;  #this is the import file - either application or a single export.
$file = glob($ARGV[0]);
if ($file eq '' && $ARGV[0] ne '') {
  $file = $ARGV[0];
}
read_mgFargo_ini();
read_act_eng();#587
read_fnt_eng();#600

#override command line options with mgFargo.ini #588
if (defined ($ini{lc(Verbose)           })){ $opt_v = $ini{lc(Verbose)};  }
if (defined ($ini{lc(numberFiles)       })){ $opt_n = $ini{lc(numberFiles)};}
if (defined ($ini{lc(uniquifyVars)      })) { $opt_u = $ini{lc(uniquifyVars)};}

if (defined ($ini{lc(useDfNamePrefixes) })){ $opt_f = $ini{lc(useDfNamePrefixes)};}

if (defined ($ini{lc(startProgram)      })){ $opt_s = $ini{lc(startProgram)}; }
if (defined ($ini{lc(endProgram )       })){ $opt_e = $ini{lc(endProgram)}; }
if (defined ($ini{lc(progList)          })){ $opt_p = $ini{lc(progList)}; chomp($opt_p)}
if (defined ($ini{lc(internalFileExport)})){ $opt_d = $ini{lc(internalFileExport)}; chomp($opt_d) }

my $rowColumnFirst   = $ini{lc(rowColumnFirst     )}; #600 doesn't necessarily need to be in mgFargo.ini - will not crash if its missing.
my $showScaledToFit  = $ini{lc(showScaledToFit    )};
my $showScaledToFill = $ini{lc(showScaledToFill   )};
my $showAllowCrInData= $ini{lc(showAllowCrInData  )};
   
my $useDfNamePrefixes = defined($opt_f)?$opt_f:0;#default is not to prepend #574
my $uniquifyVars = defined($opt_u)?$opt_u:1; #default is to uniquify #574

my @dd = ();
if ($opt_d && $opt_d ne '') {
	if ( glob($opt_d)  ne '') {
	$opt_d = glob($opt_d);
    }
}
if( $opt_d && $opt_d ne ''){
	$ddfnspec = $opt_d;
}
else{
	$ddfile = 'ddict';
}
if ($opt_p) {
  if ( glob ($opt_p) ne '' ){
	$opt_p = glob($opt_p);
   }
}
else {
	$opt_p = 'proglist';
}
print STDERR "prefixing datadictionary names\n" if $opt_f && $opt_v;

print STDOUT "...first pass. loading variables and expressions\n" if $opt_v;

open IN, "< $file ";
loadExpressions();
close IN;
close MENUS;
close DROPMENUS;
if( appExport )	{ close PRG };

print STDOUT "...second pass. writing doc files\n" if $opt_v;
$start2 = time;
open HTMLMAIN, "> mgapp-index.html";#581
select HTMLMAIN;
$~=HTML_HEADER;
write;
open IN, "< $file ";
readin();

if (/^VRSN=(\d+)/) { $magicVersion = $1; }
else{ die "no VSRN?\n";
}

$p = 0;
$indentUsed = 1;

while (readin()) {
	if ($_ eq "PRG={\n") {
		last if (defined($opt_e) && $p >$opt_e ); # pop out if we are past the end program
		writeProgram();
	}
}
close IN;
print HTMLMAIN "</table>\n</body>\n</html>\n";
close HTMLMAIN;
print STDERR "Total Run times (secs), pass1:", $start2 - $start1 . ' pass2:', time - $start2 ;

# exit here
sub varDesc {
	my $id = shift;
	my $h = $hier;
	my $desc = '?var?';

	while (1) {
		if (defined($var[$p]->{$h}->{$id}->{desc})) {
			$desc = $var[$p]->{$h}->{$id}->{desc};
			last;
		}
		elsif ($h eq '1' ) {
			last;
		}
		else {
			$h =~ s/(\.\d+)$//;   #remove one level
		}
	}
	$desc;
}
sub expandedExpression{
	my $in = shift;
	my $lastToken = 'none';
	my $result = '';
	while ($in =~ m{
			 (
			 \'\'           | # null string
			 \'[^\']*?\'    | # strings
			 IF\s\( |
			 \sOR\s |
			 \sAND\s |
			  <> |
			  <= |
			  >= |
			 [&<>\.\-+*,=\(\)\/] | # punctuation
			 [A-Z]+         | # symbols
			 [0-9.]+          #572 attempt to fix problem of spaced out decimal in 0.02 construct
			 )
		   }xg){
		$token = $1;
		if ( $token =~/IF\s\(/){
			$lastToken = 'if';			    $result .= $token . ' ';
		}
		elsif ( $token =~/\s(OR|AND)\s/){
			$lastToken = 'and-or';			    $result .= $token;
		}
		elsif ( $token =~/\'[^\']*?\'/){
			$lastToken = 'string';			$result .= $token;
		}
		elsif ($token =~ /[&<>+*,=\'\(\)\/]/){
			if (($lastToken eq 'string') && ($token eq '&')) {
				$result .= ' ';
			}
			$lastToken = 'punct';
			if( $token eq '=' ){
										$result .= '==' . ' '; #573 use equivalence. There are never assignments within expressions.
			}
			else {
										$result .= $token . ' ';
			}
		}
		else{
			if ($lastToken eq 'string'){
				$lastToken = 'const';		$result .= $token;
			}
			else{
				if ( $token =~ /^[A-Z]{1,2}$/){
					$lastToken = 'var';		$result .= varDesc($token) . ' ';
				}
				else{
					$lastToken = 'keyword';	$result .= $token . ' ';
				}
			}
		}
	}
	$result =~ s/\'([A-Z]+)\'VAR/'@' . varDesc($1)/ge; 	#0586 replace any instances of "'xx'VAR" with "@variable".
	$result;
}
sub countBrackets{
	my $count;
	my $rights = 0;
	my $lefts = 0;

	$prevline =~ s/".*?"//g;  #strip out strings so we don't get fooled by brackets inside the strings.
	while ($prevline =~ m/(\}+),/g){
		$rights += length $1;
	}
	while ($prevline =~ m/=(\{)/g){
		$lefts += length $1;
	}
	$count = $rights - $lefts;
}
sub	setHierarchicalPosition{
# EXP: no brackets => subtask, 1 => close current task and next task is on the same level. 2+ => level after ascending n-1 levels.
# TXT, ACTV, BLOCK: a surfeit of 1 bracket will close the preceding DSP. That's expected.  Any more close previous tasks.
# OLECLASS: surfeit of 1 bracket: closes prior DIT_INFO, 2: closes prior ITM, 3: closes prior DSP
# PIC (version 5): surfeit of 1 closes prior ITM, 2: closes prior DSP.
#
#0609 HTML Merge
# What I currently print:
#	Form: 13 Individual File Heading Class 4 Type:HTMLMerge, Detail, IsChild:N, Color:6, Font:1,Default Table Edit Field~MS Sans Serif~8~0, UOM_FACTOR={X=1,Y=1},
#	BLOCK={DX=100,DY=10},TMPL_FILE="%template%ruleSmInd.htm",TAG_PRFX="<!$",TAG_SUFX=">",
#	+-Row-Col-Rows-Cols-Allow------- Name -------------------Attr-Pic---------------------------+
#
# Whats in the app export
#	DSP={
#	DSP_INFO={NAME="Individual File Heading",CLSS=4,MOD=N,COLOR=6,STYLE=2048,FONT=1,ISCHLD=N,GRIDX=10,GRIDY=10},
#	UOM_FACTOR={X=1,Y=1},
#	
#	FRM={},
#	BLOCK={DX=100,DY=10},TMPL_FILE="%template%ruleSmInd.htm",TAG_PRFX="<!$",TAG_SUFX=">",
#	MERGE_PARM={EXP=1,
#	PIC="300",TXT="GeneratorProgPath"},
#	MERGE_PARM={EXP=2,
#	PIC="30",TXT="GenDateTime"},
#	MERGE_PARM={EXP=3,
#	PIC="30",TXT="LastModifiedDate"},
#	MERGE_PARM={FLD="O",
#	PIC="60",TXT="ProcessDesc"},
#	MERGE_PARM={FLD="N",
#	PIC="50",TXT="XPath"},
#	MERGE_PARM={FLD="P",
#	PIC="2000",TXT="LongDesc"}},
#	
	$length = countBrackets();
	$length -= 1 if ($prevline =~ /^(ACTV|TXT|BLOCK)/);
	$length -= 2 if ($prevline =~ /^(PIC)/);
	$length -= 3 if ($prevline =~ /^(OLECLASS)/);
	if ( $length == 0) { #add a level
		$hier .= '.1';
	}
	elsif ($length >= 1 && $hier eq '1') {
		print STDOUT "gotcha\n";
	}
	elsif ($length == 1) {
		$hier =~ s/(\d+)$/$1+1/e;   #move laterally, increment the last number
	}
	else { #move up then over
		$hier = getTaskHier( $length-1 );
		$hier =~ s/(\d+)$/$1+1/e;
	}
}
sub initTaskVarsPrescan{#for prescan
	$formNumber=0;
	$vr=0;  #virtual-real index
	$e=1;
	$j=1;
	$v=1;
	$maindbf=0;
}
sub loadExpressions{
	$e = 1;
	$loading = 'nothing';
	$appExport = 1;  #assume an Application Export
	while (<IN>){
#		s/ISN(_2)?=\d+,?//;  # version 8 may have optional ISN numbers we don't need. strip them out.
		if (!/^TSK/) {		#unique to PROGRAMS section
			$prevline = $_;
		}
		if (!/^[DEFHKLMPRST]/) {
			next;
		}
		if (/^EXP="(.*)"[,\}]/){ #unique to PROGRAMS section-match as much as possible
			printFormItem();
			$exp[$p][$t][$e] = expandedExpression($1);
			$e++;
		}
		elsif ( /^KEY=\{DESC=\"(.*?)\",/){#unique to FILES section
			ddKey($1);
		}
		elsif (/^RMRK=/){  #if the remark field contains  "LNKREF=blah", 
			# then a real field may be rendered "filename.blah_fieldname"
			if ( /LNKREF=(\w+)/) {
				$lnkref = '_' . $1;
			}
		}
		elsif ( /^FILE=\{(DBNAME|DESC|NAME)/){#unique to FILES section and there was an '=' sign on the end . Worked in Unix, Not in NT
			$opt_p = 0; # Disable reading programs from separate table if we have the whole application here.
		    open ( PRG, "< $file "); #Do 
			$loading = 'files';
			ddFile();
		}
		elsif (/^FIELD=\{DESC=\"(.*?)\",/) {  #v9 construct
			if ($loading eq 'files') {
				ddField($1);
			}
			else {
				$virt[$p][$t][$v]->{desc}= $1;
				$v++;
			}
		}
		elsif (/^PROP=\{ID=\"(.*?)\",/) {
				$v--;
				$virt[$p][$t][$v]->{pic} = $1 if $_ =~ /"PICTURE"="(.+?)"/;
#				$virt[$p][$t][$v]->{strg} = $1 if $_ =~ /STRG=(\d+)/;
				$v++;
		}
		elsif (/^FLD=\{DESC=\"(.*?)\",/) {
			if ($loading eq 'files') {
				ddField($1);
			}
			else {
				$virt[$p][$t][$v]->{desc}= $1;
				$virt[$p][$t][$v]->{pic} = $1 if $_ =~ /PIC="(.+?)"/;
#				$virt[$p][$t][$v]->{strg} = $1 if $_ =~ /STRG=(\d+)/;
				$virt[$p][$t][$v]->{type}  = $1 if $_ =~ /TYP=([0-9]+),/;
				$virt[$p][$t][$v]->{range} = $1 if $_ =~ /RNG="(.+?)",/;

				$attr = $1 if $_ =~ /ATTR=(.)/;
#				if(defined($attr) && $attr != ''){
				$virt[$p][$t][$v]->{attr} = expandIOmode( 'attr', $attr);
#				}
				$v++;

#				$attr= $1 if $_ =~ /SIZ=(\d+)/;
#				$siz = $1 if $_ =~ /RSRCE=\{MDFY=(.)/;
#				$mdfy= $1 if $_ =~ /TRNS=(.)/;
#				$trns= $1 if $_ =~ /DEF=(.)/;
#				$def = $1 if $_ =~ /MOD=(.)/;
#				$mod = $1 if $_ =~ /CTRL=(.)/;
#				$ctrl= $1 if $_ =~ /CTRL_STP="(.+?)"/;
#				$null= $1 if $_ =~ /NUL_ALW=(.)/;
			}
		}
		elsif (/^SLCT={NAME="([][A-Z\^]+)",/){ #0602  enable characters after Z, right square bracket must be first character in character class.
			$varletter = $1;
			my $desc;

			if (/FLD=(\d+),MOD=V,/){
				$desc = $virt[$p][$t][$1]->{desc};
				$var[$p]->{$hier}->{$varletter}->{type} = 'Virt';
				$var[$p]->{$hier}->{$varletter}->{'ref'} = \$virt[$p][$t][$1];
			}
			elsif (/FLD=(\d+),MOD=R,/){
				if (defined($dd[$dbf]{fields}->[$1])){
					my $ddPrefix = '';
					if ( $useDfNamePrefixes ){
						$ddPrefix = $dd[$dbf]{desc} . $ddPrefixSeparator
					}
					$desc = $ddPrefix . $dd[$dbf]{fields}->[$1];
					$var[$p]->{$hier}->{$varletter}->{type} = 'Real';
				}
				else{
					$desc = '?undefined';
				}
			}
			my $varSuffix = '';
			if ($lnkref ne '') {
				$lnkref = $lnkref;
			}
			if ($uniquifyVars){
			    my $i=0;
				while ($var[$p]->{vars}->{$desc . $lnkref . $varSuffix}){
					$i++;
					$varSuffix = '_' . $i;
				}
			}
			$desc .= $lnkref . $varSuffix;
			$var[$p]->{$hier}->{$varletter}->{desc} = $desc;
			$var[$p]->{vars}->{$desc } = 1;
			$vr++;
			$var[$p]->{$hier}->{$vr} = $desc;
		}
		elsif (/^LNK=\{DB=(\d+)/){
			$dbf = $1;
		}
		elsif (/^END_LINK/){
			$dbf = $maindbf;
			$lnkref = '';
		}
		elsif (/^DB/) {
			$maindbf = $1 if $_ =~ /DB=(\d+)/;
			$dbf = $maindbf;
		}
  	    elsif (/^HDR=/ ){  #v055
			$desc = '--';#v055
			$desc = $1 if (/\{DESC="(.+?)",/);#v055
			print STDOUT "..... $p.$1  \n" if ( $opt_v && $hier eq '1');
			if (!$opt_p || $hier ne '1') {
				$prgtaskName[$p]->{$hier}->{desc} = $1;
				$prgtaskName[$p]->{$hier}->{idx} = $t;
			}
		}
		elsif ( $_ eq 'RPR={' ){ # in report, similar to task structure, skip it.
			while (<IN>){
				if (/^PRG=/){
					unshift @saved, $_;
					last;
				}
			}
		}
		elsif (/^TSK=/){
			$t++;
			initTaskVarsPrescan();
			setHierarchicalPosition();
#			print STDOUT "hier = $hier\n";
		}
		elsif ($_ eq "PRG={\n"){
			if ($loading eq 'nothing') { #This must be a single program export. We need to load a program list
				print STDOUT "single program export. Load a program list.\n";
				$appExport = 0;
				if(  ! -f $opt_p ){ $error= "option p:file \"$opt_p\" does not exist."; usage();}
				readPrgList($opt_p);
			}
			elsif ($loading != 'programs'){ #first time in here
				open ( PRG, "< $file ");
			}
			$loading = 'programs';
			if (!$ddloaded) {
				loadDataDictionary();
			}
			initTaskVarsPrescan();
			$p++;
			$t=1;
			$hier='1';
		}
		elsif (/^DSP(?:_INFO)?=\{.*NAME="(.*?)",/) {#version 8 has the _INFO string, (#585) NAME may not directly follow the brace
			$formNumber++;
			$prgtaskName[$p]->{$hier}->{form}->[$formNumber] = $1;  #assign the name of the form.
		}
		elsif (/^RGHT=\{NAME="(.*?)",KEY="(.*?)",PBLC=(.)/) {
			$loading = 'rights';
			$rights++;
			$rights[$rights]->{name} = $1;
			$rights[$rights]->{key}  = $2;
			$rights[$rights]->{public}= $3;
		}
		elsif (/^DRPD=\{/) { #DRPD lines come at the end of an internal dump so we can reconcile them on the first pass.
			$loading = 'dropmenus';
 			if (!defined $dropmenus) {
				$indentUsed = 1;
				$dropmenus = 1;
				open DROPMENUS, ">dropdownMenus.txt";
				select DROPMENUS;
				print "\nDrop-down Menus\n";
			}
			printV5MenuEntry();
		}
		elsif (/^MNU=\{/) { #MNU lines come at the end of an internal dump so we can reconcile them on the first pass.
			printFormItem();
			$loading = 'popmenus';
 			if (!defined $menus) {
				$indentUsed = 1;
				$menus = 1;
				open MENUS, ">popupMenus.txt";
				select MENUS;
				print "\nPop-up Menus\n";
			}
			printV5MenuEntry();
		}
		elsif (/^MNUENTRY=\{/) { #MNU lines come at the end of an internal dump so we can reconcile them on the first pass.
					    #605 v8 token is MNUENTRY. Fields are same as v5, but the order is different.
			printFormItem();
			printV8MenuEntry();
		}
		elsif (/^TOOL=\{/) { #605  v8
			($brackets) = $_ =~ /(\}+)$/;
			$indentUsed -= length($brackets) - 1;
		}
		elsif (/^MENU=\{TYP=1/) { #605 v8
			$indentUsed ++;
		}
		elsif (/^MENU=\{TYP=2/) { #605 v8
			$loading = 'dropmenus';
			$indentUsed = 1;
			$dropmenus = 1;
			open DROPMENUS, ">dropdownMenus.txt";
			select DROPMENUS;
			print "\nDrop-down Menus\n";
		}
		elsif (/^MENU=\{TYP=4/) { #605 v8
			$loading = 'popmenus';
			$indentUsed = 1;
			$menus = 1;
			open MENUS, ">popupMenus.txt";
			select MENUS;
			print "\nPop-up Menus\n";
		}
#		elsif (/^OLECLASS=\{/) {
#			$x = 1;
#		}
	}
} #end of LoadExpressions
sub spaceTo{
	my ($current, $to) = @_;
	$spacing = ($current < $to)?($to-$current):1;
	print substr ($spacestr, 0, $spacing);
	$current += $spacing;
	$current;
}
sub printV5MenuEntry{
	tabOut();
	$rpos = 4 * $indentUsed;

	($type) = $_ =~ /TYP=(.)/;

	$desc = ''; $prog = 0; $ext  = ''; $actv = 0; $char = 0;

	$prog = $1 if /PRG=(\d+)/;
	$actv = $1 if /ACTV=(\d+)/;#action - see act_std.eng
	$desc = $1 if /DESC="(.*?)",/;
	$ext  = $1 if /EXT="(.*?)",/;
	$char = $1 if /CHAR=(\d+)/;

	if ($type eq 'L' ){#exits, menus, program, system types all have desc fields, only the line doesn't.
		$desc = '----------------------------------------';
	}
	print $desc;	$rpos += length($desc);
	$rpos = spaceTo($rpos, 60 );
	print "|"; $rpos++;
	$desc = '';
	# v5 Types E=Exit, P=Program, S=Action, L=Separator Line
	if ($type eq 'E' ){#exit
		$desc = "Exit to: " . $ext;
	}
	elsif($type eq 'P' ){#program
		$desc = "Call Prog: " . $prgtaskName[$prog]->{'1'}->{desc};
	}
	elsif($type eq 'S' && $actv ne ''){#action
		$desc = "Put: " . $action_from_code{$actv};
	}
	if ($desc ne '') {
		print $desc;	$rpos += length($desc);
	}
	$rpos = spaceTo($rpos, 100 );
	print '|';
	print  rights($1) if (/GRP=(\d+)/);
	print "\n";
	readin();#in v5 every DRPD or MNU line is followed by a WIN line that holds closing brackets
	($brackets) = $_ =~ /(\}+)$/;
	$indentUsed -= length($brackets) - 2;
}
sub printV8MenuEntry{
	# MENU={TYP=2 is pulldown menus
	# MENU={TYP=4 is popup menus
	# MNUENTRY Types 1=Menu, 2=Program, 3=Action, 4=Exit, 5=Separator
	# Type 1 is followed by MENU={Typ=1
	# Usually Type 3 MNUENTRY has a single bracket close, but could
	# have a Tool which would have two brackets.
	# Only a MENU= causes an indent. ignore the brackets.
	tabOut();
	$rpos = 4 * $indentUsed;

	($type) = $_ =~ /TYP=(.)/;

	$desc = ''; $prog = 0; $ext  = ''; $actv = 0; $char = 0;

	$prog = $1 if /PRG=(\d+)/;
	$actv = $1 if /ACTV=(\d+)/;#action - see act_std.eng
	$desc = $1 if /DESC="(.*?)",/;
	$ext  = $1 if /EXT="(.*?)",/;
	$char = $1 if /CHAR=(\d+)/;

	if ($type eq '5' ){#exits, menus, program, system types all have desc fields, only the line doesn't.
		$desc = '----------------------------------------';
	}
	print $desc;	$rpos += length($desc);
	$rpos = spaceTo($rpos, 60 );
	print "|"; $rpos++;
	$desc = '';
	if ($type eq '4' ){#exit
		$desc = "Exit to: " . $ext;
	}
	elsif($type eq '2' ){#program
		$desc = "Call Prog: " . $prgtaskName[$prog]->{'1'}->{desc};
	}
	elsif($type eq '3' && $actv ne ''){#action
		$desc = "Put: " . $action_from_code{$actv};
	}
	if ($desc ne '') {
		print $desc;	$rpos += length($desc);
	}
	$rpos = spaceTo($rpos, 100 );
	print '|';
	print  rights($1) if (/GRP=(\d+)/);
	print "\n";
	($brackets) = $_ =~ /(\}+)$/;
	$indentUsed -= length($brackets) - 1;
}
sub rights{
	my $i = shift;
	if (defined($rights[$i]->{name})) {
		$name = $rights[$i]->{name};
	}
	else {
		$name = '?error?';
	}
	$name;
}
sub initDataDictionary{
	$ddloaded = 1;
	$ddfile = 0;
	$dd[0]{desc}= 'None';
	$dd[0]{desc}= '0.' if $compatibilityMode;
	$dd[0]{key}->[0]= 'None';
	$dd[0]{key}->[0]= '0.' if $compatibilityMode;
}
sub ddFile{
	if (!$ddloaded) {
		initDataDictionary();
	}
	$desc = $1 if /DESC=\"(.*?)\"/;
	$name = $1 if /NAME=\"(.*?)\"/;#eg DEBUG.DAT for the DBG file
	$ddfile++;
	$ddfield = 0;
	$ddkey = 0;
	$dd[$ddfile]{desc}= $desc;
	$dd[$ddfile]{key}->[0]= 'None';
	$dd[$ddfile]{key}->[0]= '0.' if $compatibilityMode;
}
sub ddField{
	my $desc = shift;

	$ddfield++;
	$dd[$ddfile]{fields}->[$ddfield]= $desc;
}
sub ddKey {
	my $desc = shift;
	$ddkey++;
	$dd[$ddfile]{key}->[$ddkey]= $1;
}
sub loadDataDictionary{
	if( ! -f $ddfnspec ){ $error = "option d:file \"$opt_d\" does not exist"; usage();}
	print STDERR "pulling file definitions from $ddfnspec\n" if $opt_v;
	open( DD, "< $ddfnspec");
	while (<DD>){
		if ( /^FILE=\{/){
			ddFile();
		}
		elsif ( /^FLD=\{DESC=\"(.*?)\",/){
			ddField($1);
		}
		elsif ( /^KEY=\{DESC=\"(.*?)\",/){
			ddKey($1);
		}
	}
	close DD;
}



sub nextVar
{
	$currentVar++;
	my $highChar = $currentVar/26;
	my $lowChar = $currentVar % 26;

	my $highCharA = ($highChar==0)?'':chr($highChar+65);
	my $lowCharA = chr($lowChar+65);
	$currentVarA = $highCharA . $lowCharA;
}
sub tabOut{
	print substr $tabstr, 0, $indentUsed;
}
sub getWrtRead{
	my $dir = shift;

	($mode, $io, $dsp) = $_ =~ /MOD=(.),IO=\{(.+?)\},DSP=\{(.+?)\}/;
	$ioTsk = 0;
	$dspTsk = 0;
	$ioIdx = 0;
	$dspIdx = 0;
	$ioTsk  = $1 if $io  =~ /TSK=(\d+)/;
	$ioIdx  = $1 if $io  =~ /IDX=(\d+)/;
	$dspTsk = $1 if $dsp =~ /TSK=(\d+)/;
	$dspIdx = $1 if $dsp =~ /IDX=(\d+)/;

	$ioHier = getTaskHier( $ioTsk );
	$dspHier = getTaskHier( $dspTsk );

	$dsp = $prgtaskName[$p]->{$dspHier}->{form}->[$dspIdx];

	$io = $prgtaskName[$p]->{$ioHier}->{form}->[$ioIdx];
	$format = expandIOmode('ioformat', $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{'format'});
	$media =  expandIOmode('iomedia',  $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{media});
	$access = expandIOmode('mod',      $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{access});

	print "$dir Form: $dsp ON \"$prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{desc}\" $media  $access  $format  File: $prgtaskName[$p]->{$ioHier}->{io}->[$ioIdx]->{file}";

}
sub getTaskHier {
	my $levels = shift;
	my $x = $hier;

	while ($levels > 0) {
			$x =~ s/(\.\d+)$//;   #remove one level
			$levels--;
		}
	$x;
}

sub doView{

	while (readin()){
		if (/^(SUFIX|PRFIX|VIEW|BRK|DSP)/){
			unshift @saved, $_;
			last;
		}
		$indentUsed = $indentLevel if ! /^RMRK/;
		if ( /^(SLCT|LCT|RNG|RMRK|STP|LNK|END_LINK|BLOCK|CALL_TSK|EXE|UPD|WRT|READ|SCN|EXT)/){
			tabOut();
		}
		elsif (/^END_BLK/){
		}
		else{
			unshift @saved, $_;
			last;
		}
		if (/^CALL_TSK/ && ! /FLW=\{/) {  # flow not part of call, then are args
			getArgsAndFlow();
		}
		if (/^SLCT/     && ! /FLW=\{/) {  # flow not part of select
			$orig = $_;
			undef @lsaved;
			for ($i=1; $i<=2; $i++){
				readin();
				if (/^(LCT|RNG)/){
					push @lsaved, $_;
					if (/FLW=\{/){
						chomp($orig);
						$_ = $orig . $_;
						last;
					}
				}
				else{
					push @lsaved, $_;
					$_ = $orig;
					last;
				}
			}
			unshift @saved, @lsaved
		}
		$flowStr = '';

		#if ( $enableFlowStr && /FLW=\{/){
		if ( /FLW=\{/){
			$isBlock    = $_ =~ /^BLOCK=\{END/;#600
			$isSelect   = $_ =~ /^SLCT=/;
			( $flwCond, $flowMode, $flowDir ) = $_ =~ /CND=(Y|N|\d+),MOD=(.),DIR=(.)/;

			if ($enableFlowStr) {
				if (/^UPD=/){
					$defFlowSpeed = $ini{lc(defFlowSpeedUpdate)};
					$defFlowDirection = $ini{lc(defFlowDirectionUpdate)};
				}
				else{
					$defFlowSpeed = $ini{lc(defFlowSpeed)};
					$defFlowDirection = $ini{lc(defFlowDirection)};
				}
				if ( $taskFlow eq 'Online' ){
					if    ($flowMode eq $defFlowSpeed){ $flowstr = ''; }
					elsif ( $flowMode !~ /S|F|C|B|A|Z|J/) {$flowStr  = "unknown mode ?$flowMode?";     }
					else {					  	    $flowStr  = "\t// " . $flowMode{$flowMode};	}

					if    ($flowDir eq $defFlowDirection){ $flowstr .= ''; }
					elsif ( $flowDir  !~ /F|C|B/  )   {$flowStr .= ' unknown dir';  		        }
					else { 				 		    $flowStr .= ' '     . $flowDir{$flowDir};	}

				}
			}
			if ( $flwCond eq 'Y' ){
				$indentExp = 'Y';
				if ($isBlock){
					$indentLevel++;
					print "Do\n";
					tabOut();
				}
				elsif ($indentExp ne 'Y' ) {
					$indentLevel--;
					$indentExp = 'Y';
				}
			}
			else{
				if ($flwCond ne 'N') {
					if (defined(   $exp[$p][$t][$flwCond])){
						$flwCond = $exp[$p][$t][$flwCond];
					}
					else{
						$flwCond = '?undefined?';
					}
				}
				$indentLevel++;
				$indentUsed = $indentLevel;
				if ( $indentExp ne $flwCond ){
					$indentExp = $flwCond;
					if ( $flwCond eq 'N' ){
						if ($isSelect){
							print "Never do/Land on fields:\n";
							tabOut();
						}
						else {
							print "Never do:\n";
							tabOut();
						}
					}
					else{
						print "If $flwCond";
						print "\n" if !$isBlock;
						tabOut();
					}
				}
				else{ #not a new condition
					print "\t";
				}
				$indentLevel-- if ! $isBlock;
			}
		}
		# would be nice to be able to delay this output til after we determine that there is or is not
		# a locate or range expression, in order to keep the locate and range on the same line as the assign.
		if (/^SLCT=\{NAME="([A-Z]{1,2})"/){
			print "$var[$p]->{$hier}->{$1}->{type}:$var[$p]->{$hier}->{$1}->{desc}";
			if (/ASS=(\d+)/){
				print "\t=\t$exp[$p][$t][$1]";
			}
			#Add code to check if line ends with '},' because if so, nl is ok, but if not, let the locate/range add the newline.
		}
		elsif (/^RMRK="(.*?)",/){
			if ( $1 eq ''){
				print "//-------------------------------------------------------------------------";
			}
			else{
				print "// $1";
			}
		}
		elsif (/^CALL_TSK=/){
			($mode) = $_ =~ /MOD=(.),/;
			($task) = $_ =~ /TSK=(\d+),/;
			($lock) = $_ =~ /LOCK=(.)/;
			($dsp) = $_ =~ /DSP=(\d+),/;
			print "Call Prog: $prgtaskName[$task]->{'1'}->{desc}"  if $mode eq 'P';
			print "Call Task: $prgtaskName[$p]->{$hier . '.' . $task }->{desc}" if $mode eq 'T';
			print "Call Exp: $exp[$p][$t][$task]"      if $mode eq 'E';
			print "Call UDP: $exp[$p][$t][$task]"      if $mode eq 'U';
			if (defined(@args))	{
				print "$flowstr";
				$i = 1;
				foreach $arg (@args){
					print "\n";
					tabOut();
					printf( "\t% 3d|%s", $i, $arg);
					$i++;
				}
				$flowstr = '';
				undef(@args);
			}
		}
		elsif (/^STP=/){
			print "Put Warning " if $_ =~ /MOD=(V|W)/;
			print "Put Error   " if $_ =~ /MOD=E/;

			print $1 if $_ =~ /TXT="(.*?)",/;
			print $exp[$p][$t][$1] if $_ =~ /EXP=(\d+)/;
		}
		elsif (/^LNK=/){
			$db = 0;
			$key = 0;
			$dir = '';
			$cls = 0;
			$views = 0;
			$view = 0;
			$mod = 0;
			$rtrn ='';

			$db    = $1 if /DB=(\d+)/;
			$key   = $1 if /KEY=(\d+)/;
			$dir   = $1 if /DIR=(.)/;
			$cls   = $1 if /CLS=(\d+)/;
			$views = $1 if /VIEWS=(\d+)/;
			$view  = $1 if /VIEW=(\d+)/;
			$mod   = $1 if /MOD=(.)/;
			$rtrn  = $1 if /RTRN="(.+)"/;


			print "Link ";
			if    ($mod eq 'R'){ print "Query   ";  }
			elsif ($mod eq 'W'){ print "Write   ";  }
			elsif ($mod eq 'N'){ print "Validate";  }
			elsif ($mod eq 'A'){ print "Create  ";  }
			print " : $db $dd[$db]{desc}  Key: $key $dd[$db]->{key}->[$key]  Dir: $dir";
			my $var = varDesc $rtrn;

			print "   Returning: $var"  if $rtrn ne '';

			$indentLevel++;
		}
		elsif (/^END_LINK,/){
			$indentLevel--;
			$lnkref = '';
		}
		elsif (/^BLOCK=\{END/){
		}
		elsif (/^END_BLK/){
			$indentLevel--;
		}
		elsif (/^EXE=\{EXP=(\d+)/){
			$exp =  $1;
			print "Evaluate: $exp[$p][$t][$1]";
			$rtrn  = $1 if /,FLD="(.+)"/;
			my $var = varDesc $rtrn;

			print "   Returning: $var"  if $rtrn ne '';
		}
		elsif (/^UPD=/){
			($fld, $exp, $mode, $abort ) = $_ =~ /FLD="(.+)",EXP=(\d+),MOD=(.),ABRT=(.)/;
			$inc = ( $mode eq 'I' )?'+':'';
			print varDesc($fld) . "\t$inc=\t$exp[$p][$t][$exp]";
			if ( $complete) {
				print "\t//$mode,$abort";
			}
		}
		elsif (/^WRT=/){
			getWrtRead( 'Output' );
		}
		elsif (/^READ=/){
			getWrtRead( 'Input' );
		}
		elsif (/^SCN=/){
			$exp = 0;
			$dsp = 0;
			$mod = '';
			$edit = '';
			$exp = $1 if /EXP=(\d+)/;
			$dsp = $1 if /DSP=(\d+)/;
			$mod = $1 if /MOD=(.)/;
			$edit = $1 if /EDIT=(.)/;
			$edit = $edit eq 'S'?'Scan':'Edit';
			print "Browse $edit $exp[$p][$t][$exp]";
		}
		elsif (/^EXT=/){
			($exp) = $_ =~ /EXP=(\d+),/;
			$wait = '';
			$show = '';
			$rtrn = '';
			$clr  = '';
			
			print "Exit to: $exp[$p][$t][$exp]";
			$wait  = $1 if /,WAIT=(.)/;
			$show  = $1 if /,SHOW=(.)/;
			$rtrn  = $1 if /,RTRN="(.+)"/;
			my $var = varDesc $rtrn;
			
			print "  Returning: $var"  if $rtrn ne '';
			print "  Wait  " if $wait = 'Y' && $wait ne $ini{lc(defExeWait)} ;
			print "  Hide  " if $show eq 1  && $show ne $ini{lc(defExeShow)} ;
			print "  Normal" if $show eq 2  && $show ne $ini{lc(defExeShow)} ;
			print " Clearscn" if $clr eq 'Y'  && $clr ne $ini{lc(defExeShow)} ;
		}
#		elsif (/^EXT=/){
#			$exp='';
#			$clr='';
#			$wait='';
			
#			($exp) = $1 if $_ =~ /EXP=(\d+)/;
#			print "Exit to: $exp[$p][$t][$exp]";
#			if ( $_ =~ /CLR=(.)/){
#				if ($1 == 'Y') {
#					print " and clear the screen";
#				}
#				else {
#					print " and do not clear the screen";
#				}
#			}
#			if ( $_ =~ /WAIT=(.)/) {
#				if (!defined ($ini{lc(defExitToWait)}) ) {
#					$ini{lc(defExitToWait)} = '';
#				}
#				if ($1 == 'Y') {
#					print " and wait for completion" if $ini{lc(defExitToWait)} != 'Y';
#				}
#				else {
#					print " and do not wait for completion" if $ini{lc(defExitToWait)} != 'N';
#				}
#			}
#		}
		elsif (/^LCT=/){ #fix this to resemble range which looks correct
			$min ='';
			$max ='';
			$min = $1 if $_ =~ /MIN=(\d+)/;
			$max = $1 if $_ =~ /MAX=(\d+)/;
			if ($min eq $max ){
				print "\tLocate == $exp[$p][$t][$min]\n"; #573 changed to == equivalence
				tabOut();
			}
			else {
				if ($min ne '')	{ 
					print "\tLocate From: $exp[$p][$t][$min]";
					if ($max ne ''){
						print "\n";
						tabOut();
					}
				}
				print "\tLocate   To: $exp[$p][$t][$max]" if $max ne '';
			}
		}
		elsif (/^RNG=/){
			$min ='';
			$max ='';
			$min = $1 if $_ =~ /MIN=(\d+)/;
			$max = $1 if $_ =~ /MAX=(\d+)/;
			if ($min eq $max ){
				print "\tRange = $exp[$p][$t][$min]\n";
				tabOut();
			}
			elsif(1){
				#57  add code to put from and to on same line, also do for locate.
				if ($min ne '' || $max ne '')	{
					if ($min ne '' || $max ne '')	{
						print "\tRange ";
					}
				}
				if ($min ne '' )	{
					print "From: $exp[$p][$t][$min] ";
				}
				if ($max ne ''){
					print "To: $exp[$p][$t][$max]"
				}
				print "\n";
				tabOut();
			}
			elsif(0){
				#57  old code getting replaced
				if ($min ne '')	{
					print "\tRange From: $exp[$p][$t][$min]";
					if ($max ne ''){
						print "\n";
						tabOut();
					}
				}
				if ($max ne ''){
					print "\tRange   To: $exp[$p][$t][$max]"
				}
			}
		}
		print "$flowStr\n" if (!/^END_(BLK|LINK)/ );
	}
}
sub	doBreak{
	$context = 'Record';
	while (readin()){
		$indentLevel = 1;
		$indentExp = 'Y';
		if (/^VIEW=/){
			print "\nOperations: $context Main\n";
			$enableFlowStr = 1;
			doView();
		}
		elsif (/^PRFIX=/){
			print "\nOperations: $context Prefix\n";
			$enableFlowStr = 0;
			doView();
		}
		elsif (/^SUFIX=/){
			print "\nOperations: $context Suffix\n";
			$enableFlowStr = 0;
			doView();
		}
		elsif (/^(DSP|DRPD)/) { # there was an '=' sign on the end . Worked in Unix, Not in NT
			unshift @saved, $_ ;
			last;
		}
		elsif (/^BRK/) {
			if (/FLD="([A-Z]+)"/) {
				$context = 'On Change of ' . $var[$p]->{$hier}->{$1}->{desc} ;
			}
			else {
				$context = 'Task';
			}
		}
	}
}
sub doFlow{
	while (readin()){
		if (/^BRK/){
			doBreak();
		}
		elsif (/^(DSP|DRPD)/) { # there was an '=' sign on the end . Worked in Unix, Not in NT
			unshift @saved, $_ ;
			last;
		}
	}
}

format HTML_HEADER =
<HTML>
   <HEAD>
      <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
      <META NAME="Author" CONTENT="mgFargo">
	<TITLE>Application Directory</TITLE>
	</HEAD>
	<BODY>
	<H2>Application Program Files</h2>
	<TABLE WIDTH="100%" >
.

#New FORMAT formats which lead off with row colum.	     
format NFORM_DETAIL_L =
| @>> @>> @>> @>> @>> @>>>>>>>>>:                                    @>>>> @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $row, $col,$rows,$cols,$allowInput,$item,                  $attr,$pic,    $picExp,                $otherCtlCharacteristics
|                                @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                        $it
.

format NFORM_DETAIL_S =
# +-Row+-Col+Rows+Cols+Allow+-------- Name -------+Attr+-- Pic --+--------Pic-Exp--------\n";
| @>> @>> @>> @>> @>> @>>>>>>>>>:@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>> @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $row, $col,$rows,$cols,$allowInput,$item,   $it,         $attr,$pic,    $picExp,                $otherCtlCharacteristics
.

#600
format NFORM_STATICS =
| @>> @>> @>> @>>     @>>>>>>>>>:@<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<< @>>>> @<<<<<<<<<<<<<<<<<<<<< onReturn: @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $row, $col,$rows,$cols,$item,   $it,                   $fldDesc,             $attr, $pic,                            $pb_action_str,      $otherCtlCharacteristics
.
#600
format NFORM_STATICS_L =
| @>> @>> @>> @>>     @>>>>>>>>>:                       @<<<<<<<<<<<<<<<<<<<<< @>>>> @<<<<<<<<<<<<<<<<<<<<< onReturn: @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $row, $col,$rows,$cols,$item,                         $fldDesc,             $attr, $pic,                            $pb_action_str,      $otherCtlCharacteristics
|                                @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                 $it
.
#600
format NFORM_PUSHBUTTON =
| @>> @>> @>> @>>     @>>>>>>>>>:@<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>> @<<<<<<<<<<<<<<<<<<<<< onReturn: @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $row, $col,$rows,$cols,$item,   $it,                                        $attr, $pic,                            $pb_action_str,      $otherCtlCharacteristics
.
#600
format NFORM_CheckBox =
| @>> @>> @>> @>> @>> @>>>>>>>>>:@<<<<<<<<<<<<<<<<< Label:@<<<<<<<<<<<<<<< onReturn: @<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $row, $col,$rows,$cols,$allowInput,$item,       $it,  $itm_txt,             $pb_action_str.      $otherCtlCharacteristics
.
		       
#Original FORMAT formats
format FORM_DETAIL_L =
| @<<<<<:                        @<<<< @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @>>> @>>> @>>> @<<< @>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $item,                       $attr,$pic,    $picExp,               $row, $col,$rows,$cols,$allowInput,$otherCtlCharacteristics
|      @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
      $it
.

format FORM_DETAIL_S =
#      +-------- Name -------+Attr+-- Pic --+--------Pic-Exp--------+-Row+-Col+Rows+Cols+Allow+\n";
| @<<<<<: @<<<<<<<<<<<<<<<<<<<<< @<<<< @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @>>> @>>> @>>> @<<<  @>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 $item,   $it  ,              $attr,$pic,    $picExp,                $row,$col,$rows,$cols,$allowInput,$otherCtlCharacteristics
.

#587
format FORM_STATICS =
| @<<<<<<<<<: @<<<<<<<<<<<<<<<<<<<<< at:  @>>>, @>>> dimension: @>>>, @>>>> returnaction: @>>> @<<<<<<<<<<<<<<<<<<
 $item,      $pic,                  $row,$col,             $rows,$cols,$pb_action, $pb_action_str
.
#600
format FORM_CheckBox =
| @<<<<<<<<<: @<<<<<<<<<<<<<<<<< Label: @<<<<<<<<<<<<<<< at:  @>>>, @>>> dimension: @>>>, @>>>> returnaction: @>>> @<<<<<<<<<<<<<<<<<<
 $item,       $it,                      $itm_txt,             $row,$col,             $rows,$cols,$pb_action, $pb_action_str
.


sub pickUpCommonDisplayFields {

#	$col = '';	$row = '';	$rows = '';	$cols = '';	$color = '';  $attr = ''; $editType = '';
	$col = 0;	$row = 0;	$rows = '';	$cols = '';	$color = '';  $attr = ''; $editType = ''; #603

	$col   = $1 if /[{,]X=(\d+)/;
	$row   = $1 if /[{,]Y=(\d+)/;
	$cols  = $1 if /DX=(\d+)/;
	$rows  = $1 if /DY=(\d+)/;
	$color = $1 if /COLOR=(\d+)/;
	$attr  = expandIOmode('attr', $1) if /ATTR=(.),/;
	$editType  = expandIOmode('editControl', $1) if /TYPE=(.),/;
}
sub	doDisplay{
	my $formNumber = 0;
	print "\nDisplay Items\n";
	print "      +-------- Name -------+Attr+-- Pic --+--------Pic-Exp--------+-Row+-Col+Rows+Cols+Allow+\n" if (!$rowColumnFirst);
	while (readin()){
		if (/^FRM/){#600:pick up form dimensions
			print "\nTableColumnWidths=$wcols" if defined $wcols;
			undef $frm_y,$frm_dx,$frm_dy;
			($frm_y,$frm_dx,$frm_dy ) = $_ =~ /FRM={Y=(\d+),DX=(\d+),DY=(\d+)/;
			print ", y=$frm_y" if( defined($frm_y));
			print ", dx=$frm_dx" if( defined($frm_dx));
			print ", dy=$frm_dy" if( defined($frm_dy));
			print "\n";
		}
		elsif (/^ROW_H/){
			chomp;
			print "$_"; #600. Want the newline
		}
		elsif (/^BLOCK/){ #Form Detail header
			print $_; #600. Want the newline
			if ($frm_style == 'HTMLMerge'){#0609
				print "TagName\tPicture\tReplaceWith\n";
			}
			else {
			print "+-Row-Col-Rows-Cols-Allow------- Name -------------------Attr-Pic---------------------------+\n" if ($rowColumnFirst);
			}
		}
		elsif (/^ACTV/){
		}
		elsif (/^MERGE_PARM/){#0609
			my $picExp;
			undef $picExp;
			undef $fld;
			undef $exp;
			undef $pic;
			$fld = $1 if $_ =~ /FLD="([A-Z]+)"/;
			$exp = $1 if $_ =~ /\{EXP=(\d+)/;
			$mergeString = varDesc($fld) if defined($fld);
			$mergeString = "Expr: " . $exp[$p][$t][$exp] if defined($exp);
			$picExp = $1 if /TEXP=(\d+)/;
			$pic = $exp[$p][$t][$picExp]; #Actually an expression defining the picture.
			readin() if !defined($picExp);  #if TEXP is defined, there will be no separate line for PIC and TXT.
			$pic = $1 if /PIC="(.+?)"/;
			$txt = $1 if /TXT="(.*?)"/;
			print "$txt\t$pic\t$mergeString\n";
		}
		elsif (/^ITM=/){
			printFormItem();
			undef $fld;
			$attr = '';
			$pic = '';
			$fldDesc = '';
			$fld = $1 if /FLD="(.+?)"/;
			if ($magicVersion <= 599 ){
				pickUpCommonDisplayFields();
			}
			if (defined($fld)) {
				$it =  varDesc($fld);
				$fldDesc = $it;#600: initially for checkboxes
				$item = 'Field';
			}
			else {
				$item = 'Expr';
			}
		}
		elsif (/^DBOX=/) {	#version 600+
			pickUpCommonDisplayFields();
		}
		elsif (/^DIT_INFO=/) {	#version 600+
			$clr = 0; $font = 0; $style = 0; $misc = 0; $align = 0; $para_align = 0; $dit_name = ''; $isn = 0; $static=0; $pb_action = 0; $pb_action_str = ''; #587
			$DIT_layer=0;$DIT_isnFather=0;#600
			
			$clr			= $1 if /CLR=(\d+)/;	#587  #NOTE That font, color, visibility, enable can all be expressions.
			$font			= $1 if /FONT=(\d+)/;	#587
			$style			= $1 if /STYLE=(\d+)/;	#587
			$misc			= $1 if /MISC=(\d+)/;	#587
			$align			= $1 if /ALIGN=(\d+)/;	#587
			$para_align		= $1 if /PARA_ALIGN=(\d+)/;	#587
			$dit_name		= $1 if /DIT_NAME="(.*?)"/;
			$isn			= $1 if /ISN=(\d+)/;	#587
			$static			= $1 if /STATIC=(\d+)/;	#587
			$pb_action		= $1 if /PB_ACT=(\d+)/; #587
			$pb_action_str  = $action_from_code{$pb_action};
			$DIT_layer      = $1 if /LAYER=(\d+)/;	#600
			$DIT_isnFather  = $1 if /ISN_FATHER=(\d+)/;	#600
			#print STDOUT " dbox $pic editType:$editType pb_act: $pb_action isn:$isn\n";

			if    ($editType eq 'Static'){
				if    ($static == 1     ){ $editType = 'Rectangle';	}
				elsif ($static == 4     ){ $editType = 'Ellipse';	}
				elsif ($static == 8     ){ $editType = 'Line';	}
				elsif ($static == 128   ){ $editType = 'Group';	}
				else  { 				   $editType = 'Text';	}
			}
			elsif ($editType eq 'Slider'){
				if    ($style & 16384   ){ $editType = 'VertSlider'; }
				else                     { $editType = 'HorizSlider';	 }
			}
			elsif ($editType eq 'Radio'){
				if    ($style & 256     ){ $editType = 'Radio'; }
				elsif ($style & 512     ){ $editType = 'ComboBox'; }
				elsif ($style & 1024    ){ $editType = 'Tab'; }
				elsif ($style & 32768   ){ $editType = 'ListBox'; }
			}
			#600
			$frm_fnt = $font;
			makeFontString()      if defined($frm_fnt);

			if    ( $style & 0x01) { $ctl_style = '3DRaised';}
			elsif ( $style & 0x02) { $ctl_style = '3DSunken';}
			else                   { $ctl_style = '2D'       ;}
						 			  
			if    ( $style & 0x04) { $ctl_border = 'ThinBorder';}
			elsif ( $style & 0x08) { $ctl_border = 'ThickBorder';}
			else                   { $ctl_border = 'NoBorder'   ;}
						 			  
			$ctl_ScaledToFit = 0;	 			  
			if    ( $style &  0x0100000) { $ctl_ScaledToFit = 1 ;}
			$ctl_ScaledToFill = 0;	 			  
			if    ( $style &  0x0200000) { $ctl_ScaledToFill = 1 ;}
			$ctl_AllowCrInData = 0;	 			  
			if    ( $style & 0x04000000) { $ctl_AllowCrInData = 1 ;}

			$alignText ='';
			if ($align & 0x01   ){ $alignText .= "HLeft,";}
			if ($align & 0x02   ){ $alignText .= "HRight,";}
			if ($align & 0x04   ){ $alignText .= "HCenter,";}
			if ($align & 0x08   ){ $alignText .= "VTop,";}
			if ($align & 0x010  ){ $alignText .= "VCenter,";}
			if ($align & 0x020  ){ $alignText .= "VBottom,";}
			if ($align & 0x0100 ){ $alignText .= "Tabcontrolside:Top,";}
			if ($align & 0x0200 ){ $alignText .= "Tabcontrolside:Bottom,";}
			if ($align & 0x0400 ){ $alignText .= "Tabcontrolside:Left,";}
			if ($align & 0x0800 ){ $alignText .= "Tabcontrolside:Right,";}
			if ($para_align & 0x01 ){$alignText .= "PLeft,";}
			if ($para_align & 0x02 ){$alignText .= "PRight,";}
			if ($para_align & 0x04 ){$alignText .= "PCenter,";}

			if ( $item !~ /Pushbutton/){
				if($fldDesc ne ''){
					$it = $fldDesc; $fldDesc ='';
				}
				elsif ( $exp ne '') {
					$it = $exp[$p][$t][$exp]; $exp = '' ;
				}
				else {
					$it = '';#A signal so the $itm_txt is moved in
				}
			}

			$otherCtlCharacteristics = '';
			$otherCtlCharacteristics .=	"FieldExp={"     . $exp[$p][$t][$exp]. '}' if (defined($exp) && $exp>0 && $item ne 'Field');
			$otherCtlCharacteristics .= " $ctl_style"   if defined $ctl_style;
			$otherCtlCharacteristics .= ", $ctl_border" if defined $ctl_border;

			$otherCtlCharacteristics .=	", $fontString" if defined($frm_fnt);
			$otherCtlCharacteristics .=	", FontExp={"    . $exp[$p][$t][$itmExp_fntExp] . '}'    if (defined($itmExp_fntExp) && $itmExp_fntExp>0);

			$otherCtlCharacteristics .=	", Color:$clr" if defined($clr);
			$otherCtlCharacteristics .=	", ColorExp={"   . $exp[$p][$t][$itmExp_clrExp]. '}' if (defined($itmExp_clrExp) && $itmExp_clrExp>0);
			$otherCtlCharacteristics .= ", ToolTipExp={" . $exp[$p][$t][$itmExp_tooltipExp]. '}' if(defined($itmExp_tooltipExp) && $itmExp_tooltipExp>0);
			$otherCtlCharacteristics .= ", EnableIf={"   . $exp[$p][$t][$itmExp_EnableExp ]. '}' if(defined($itmExp_EnableExp) && $itmExp_EnableExp>0);
			$otherCtlCharacteristics .= ", VisibleIf={"  . $exp[$p][$t][$itmExp_VisExp ]. '}' if(defined($itmExp_VisExp) && $itmExp_VisExp>0);
			$otherCtlCharacteristics .= ", RangeExp={"   . $exp[$p][$t][$itmExp_RngExp ]. '}' if(defined($itmExp_RngExp) && $itmExp_RngExp>0);

			$otherCtlCharacteristics .=	", $alignText";
			$otherCtlCharacteristics .=	", Tab=$isn" if (defined($isn) && $isn>0);
			$otherCtlCharacteristics .=	", Father=$DIT_isnFather" if (defined($DIT_isnFather) && $DIT_isnFather>0);
			$otherCtlCharacteristics .=	", Layer=$DIT_layer" if (defined($DiT_layer) && $DiT_layer>0) ;

			$otherCtlCharacteristics .=	", PDOD=$pdod_txt" if (defined($pdod_txt) && $pdod_txt!='');

			$otherCtlCharacteristics .=", ScaledToFit:$ctl_ScaledToFit"   if  $showScaledToFit;
			$otherCtlCharacteristics .=", ScaledToFill:$ctl_ScaledToFill" if  $showScaledToFill;
			$otherCtlCharacteristics .=", AllowCRInData:$AllowCrInData"   if  $showAllowCrInData;
		}
		elsif (/^PLACE/){
			$printFormItem = 1;
			$itm_txt = $1 if /TXT="(.*)"\},/;
			$place_x = $1 if /[{,]X=(\d+)/;
			$place_y = $1 if /[{,]Y=(\d+)/;
			$place_dx = $1 if /DX=(\d+)/;
			$place_dy = $1 if /DY=(\d+)/;
			$otherCtlCharacteristics .= ',Place:' if ($place_x . $place_x  . $place_x . $place_x  . $place_x != '');
			$otherCtlCharacteristics .=  "X=$place_x," if $place_x;
			$otherCtlCharacteristics .=  "Y=$place_y," if $place_y;
			$otherCtlCharacteristics .=  "DX=$place_dx," if $place_dx;
			$otherCtlCharacteristics .=  "DY=$place_dy," if $place_dy		;
			if ( $item !~ /(CheckBox|Field|Expr)/) {
				$it = $itm_txt;
			}
		}
		elsif (/TXT="(.+?)"}/ || /^OLECLASS/) {	#was simply /^TXT=/ but made more general for version 8 #0576
			$itm_txt = $1;
			$~ = 'FORM_DETAIL_S' if (!$rowColumnFirst);
			$~ = 'NFORM_DETAIL_S' if( $rowColumnFirst);
			$printFormItem = 1;
			if ($magicVersion <= 599 ){  #something may not be right here.  Not picking up all plain text fields.
			    $it = $itm_txt;
			    pickUpCommonDisplayFields();
				$cols = length($it);#603. Static text never has a DX tag. Simply the length of the string.
			    $rows = 1;#603.  Its static text, always one row.
			    $item = 'text';
			    if (length($it) > 22 && !$rowColumnFirst){
				    $~ = 'FORM_DETAIL_L';
			    }
			    if (length($it) > 35 && $rowColumnFirst){
				    $~ = 'NFORM_DETAIL_L' if( $rowColumnFirst);
			    }
			    printFormItem();#603 In 5.xx these are standalone.
			}
			else{ # >= 600
				$item = $editType;
				if ( $item =~ /Text|Table|Rectangle|Ellipse|Line|Group|Text/ ){#600
					$attr = '';
				}
				if( $item =~ /Rectangle|Ellipse|Line|Group|Text/ ){
					$fldDesc = '';
				}
				if ( $item !~ /CheckBox|Field|Expr|Pushbutton/) {
					$it = $itm_txt;
				}
				if ( $item !~ /Pushbutton/ && $it ne '') {
					$it = $itm_txt;
				}
				if (length($it) > 22 && !$rowColumnFirst){
					$~ = 'FORM_DETAIL_L';
				}
				if (length($it) > 35 && $rowColumnFirst){
					$~ = 'NFORM_DETAIL_L' if( $rowColumnFirst);
				}
				if ($item !~ /(Text|Field|Expr|Table)/) {
					$~ = 'FORM_STATICS' if (!$rowColumnFirst);
					$~ = 'NFORM_STATICS' if( $rowColumnFirst);
					if (length($it) > 22 && $rowColumnFirst){
						$~ = 'NFORM_STATICS_L';
					}
				}
				if ($item eq 'CheckBox') {
					$~ = 'FORM_CheckBox' if (!$rowColumnFirst);
					$~ = 'NFORM_CheckBox' if( $rowColumnFirst);
				}
				if ($item eq 'Pushbutton') {
					$~ = 'FORM_Statics'     if (!$rowColumnFirst);
					$~ = 'NFORM_PUSHBUTTON' if( $rowColumnFirst);
				}
			}
			if( !$printFormItem){
				#write;
				undef($text );
				undef($itm_txt );
				undef($exp_txt );
				undef($row );
				undef($col );
				undef($rows );
				undef($cols );
				undef($pic );
				undef($attr );
				undef($color );
			}
		}
		elsif (/^PIC=|^EXP=\{/){#EXP={ will sometimes exist in absense of PIC.
			if ($magicVersion >= 600){
				my $save = $_;
				chomp($_);
				readin();
				if ( !/^EXP/){
					unshift @saved, $_ ;
				}
				else{
					$save .= $_; #concatenate the EXP line onto the end of PIC so it processes the same whether its 5.xx of 8.xx.
				}
				$_ = $save;
			}
			$pic = '';
			$hlp = '';
			$exp = '';
			$exptxt = '';#600
			$prg = '';
			$mod = '';
			$allowInput = '';
			$mst = '';
			$ctrl = '';
			$ctrlstp  = '';
			$itmExp_clrExp =0;
			$itmExp_tooltip ='';
			$itmExp_fntExp =0;
			$itmExp_tooltipExp =0;
			$itmExp_EnableExp 	=0;
			$itmExp_VisExp 	=0;
			$itmExp_RngExp 	=0;

			$pic 		= $1 if /PIC="(.+?)"/;
			$hlp 		= $1 if /HLP=(.+?),/;
			$exp 		= $1 if /EXP=(\d+)/;
			$exptxt 	= $1 if /TXT=(.+?),/;#592
			$prg 		= $1 if /PRG=(.+?),/;
			$mod 		= $1 if /MOD=(.+?),/;
			$inp 		= $1 if /INP=(.+?),/;
			$mst 		= $1 if /MST=(.+?)\}/;
			$ctrl 		= $1 if /CTRL=(.+?),/;
			$ctrl_stp 	= $1 if /CTRL_STP="(.+?)"/;
			$pdod 		= $1 if /PDOD=(\d+)/;
			$itmExp_clrExp	= $1 if /CEXP=(\d+)/;
			$itmExp_tooltip = $1 if /TOOLTIP=(.)/;
			$itmExp_tooltipExp = $1 if /TOOLTIP_EXP=(\d+)/;
			$itmExp_fntExp 	= $1 if /FNT_EXP=(\d+)/;
			
			$itmExp_EnableExp 	= $1 if /INPNE_EXP=(\d+)/;
			$itmExp_VisExp 	= $1 if /VISIBLE=(\d+)/;
			$itmExp_RngExp 	= $1 if /RNG_EXP=(\d+)/;

			if (!defined($text )) {		$text  ='';	}
			if (!defined($exptxt)) {	$exptxt   ='';	}#600
			if (!defined($row  )) {		$row   ='';	}
			if (!defined($col  )) {		$col   ='';	}
			if (!defined($rows )) {		$rows  ='';	}
			if (!defined($cols )) {		$cols  ='';	}
			if (!defined($pic )) {		$pic  ='';	}
			if (!defined($attr )) {		$attr  ='';	}
			if (!defined($color)) {		$color ='';	}

			# Picture Detailed Options Data
			$pdod_txt='';
			if($pdod & 0x01 ){ $pdod_txt .='No Negative,';}
			if($pdod & 0x02 ){ $pdod_txt .= 'Commas,'; }
			if($pdod & 0x04 ){ $pdod_txt .= 'Zero fill,'; }
			if($pdod & 0x08 ){ $pdod_txt .= 'Left justify,'; }
			if($pdod & 0x10 ){ $pdod_txt .= 'Decimal point given,'; }
			if($pdod & 0x40 ){ $pdod_txt .= 'LongAlpha';}# 64 range is given for an alfa field and it is displayed longer than its original length'; }
			if($pdod & 0x80 ){ $pdod_txt .= 'Special';}#	128 Special negative or positive sign or suffix of a number or
			#										the length of a string it is displayed longer or shorter than its original length or
			#										there are some special character in the picture

			if ($item eq 'Field') {
			}
			elsif ( $item eq 'Expr' ) {
				$it = $exp[$p][$t][$exp];
			}
			else{
				print "missed item\n";
			}
			$~ = 'FORM_DETAIL_S' if (!$rowColumnFirst);
			$~ = 'NFORM_DETAIL_S' if( $rowColumnFirst);
			if (length($it) > 22 && !$rowColumnFirst){
				$~ = 'FORM_DETAIL_L';
			}
			if (length($it) > 35 && $rowColumnFirst){
				$~ = 'NFORM_DETAIL_L' if( $rowColumnFirst);
			}
			if ($magicVersion <= 599 ){
				write;
				undef($text );
				undef($itm_txt );
				undef($row );
				undef($col );
				undef($rows );
				undef($cols );
				undef($pic );
				undef($attr );
				undef($color );
			  }
		  }
		elsif (($name, $class)= $_ =~ /^DSP(?:_INFO)?=\{.*NAME="(.*?)",(?:CLSS=(\d+))?/) {#600:let there random text between INFO= and NAME - there's another line like this one.
			#0609  PRINTING THE FORMS HERE
			undef $wcols;#600
			$formNumber++;
			print "\nForm: $formNumber $name";#600
			print " Class $class" if defined($class);
			#600 all
			print " Class 0" if !defined($class);
			undef $frm_mod, $frm_clr, $frm_sty, $frm_fnt, $frm_chld; #600
			$frm_mod = $1 if $_ =~ /MOD=(.)/;
			$frm_clr = $1 if $_ =~ /COLOR=(\d+)/;
			$frm_sty = $1 if $_ =~ /STYLE=(\d+)/;
			$frm_fnt = $1 if $_ =~ /FONT=(\d+)/;
			$frm_chld = $1 if $_ =~ /ISCHLD=(.)/;

			if    ( $frm_sty & 0x04	     ) { $frm_style = 'Java';}
			elsif ( $frm_sty & 0x08	     ) { $frm_style = 'HTMLFrameSet';}
			elsif ( $frm_sty & 0x10	     ) { $frm_style = 'GUI';}
			elsif ( $frm_sty & 0x80	     ) { $frm_style = 'WebOnlineResponse';}
			elsif ( $frm_sty & 0x800     ) { $frm_style = 'HTMLMerge';}
			elsif ( $frm_sty & 0x2000000 ) { $frm_style = 'TextBased';}
			elsif ( $frm_sty & 0x40000000) { $frm_style = 'HTMLDocument';}
			elsif ( $frm_sty & 0x60000000) { $frm_style = 'HTML';}
			else                           { $frm_style = 'Online'   ;}

			if    ( $frm_sty & 0x20	     ) { $frm_style .= ',ThinBorder';}
			elsif ( $frm_sty & 0x40	     ) { $frm_style .= ',ThickBorder';}

			if    ( $frm_sty & 0x100     ) { $frm_style .= ',SystemMenu';}
			if    ( $frm_sty & 0x200     ) { $frm_style .= ',Minimize';}
			if    ( $frm_sty & 0x400     ) { $frm_style .= ',Maximize';}
			
			if    ($frm_mod eq 'H') { $frm_mod = 'Header' ;}
			elsif ($frm_mod eq 'F') { $frm_mod = 'Footer' ;}
			elsif ($frm_mod eq 'N') { $frm_mod = 'Detail' ;}
			elsif ($frm_mod eq 'P') { $frm_mod = 'PageHeader' ;}
			elsif ($frm_mod eq 'G') { $frm_mod = 'PageFooter' ;}
			else                    { $frm_mod = '??' ;}

			print " Type:$frm_style, $frm_mod";
			print ", IsChild:$frm_chld" if defined($frm_chld);
			print ", Color:$frm_clr" if defined($frm_clr);
			makeFontString()      if defined($frm_fnt);
			print ", $fontString" if defined($frm_fnt);

			#print "\n"; #600
		}
		elsif (/^UOM/){#600
			undef $frm_uom_x, $frm_uom_y, $ndiv;
			($frm_uom_x, $frm_uom_y )= $_ =~ /X=(\d+),Y=(\d+)/;
			($ndiv )= $_ =~ /NDIV=(\d+)/; 
			chomp($_);
			print ", $_";
		}
		elsif (/^WCOLS/){#600
			$wcols .= ',' if defined $wcols;
			($width) = $_ =~ /WIDTH=(\d+)/;
			$wcols .= $width;
		}
		elsif (/^(EXP=\"|TSK|DRPD)/ || ($_ eq "PRG=\{\n")){  # there was an '=' sign on the end . Worked in Unix, Not in NT
			printFormItem();
			unshift @saved, $_ ;
			last;
		}
	}
}

sub readin
{
	$_ = shift @saved;
	if ( !defined ($_ )) {
		$_ = <IN>;
 	}
	study;
	if (!/^TSK=/) {
		$prevline = $_;
	}
	if ($_ eq "RPR=\{"){ # in report, similar to task structure, skip it.
		while (<IN>){
			if (/^PRG=/){
				last;
			}
		}
	}
#	s/ISN(_2)?=\d+,?//;  # version 8 may have optional ISN numbers we don't need.
	$_;
}
sub expandIOmode {
	($func, $val) = @_;

	if ($val eq '')	{
		$val;
		return;
	}
#	if ($func eq 'style') {
#	    if ($val &   1 )  { $val = 'style1'; }
#	    if ($val &   2 )  { $val = 'style2'; }
#	    if ($val &   4 )  { $val = 'style4'; }
#	    if ($val &   8 )  { $val = 'style8'; }
#	    if ($val &  0x10 ){ $val = 'style0x10'; }
#	    if ($val &  0x20 ){ $val = 'style0x20'; }
#	    if ($val &  0x40 ){ $val = 'style0x40'; }
#	    if ($val &  0x80 ){ $val = 'style0x80'; }
#	    if ($val &  0x100){ $val = 'style0x100'; }
#	    if ($val &  0x200){ $val = 'style0x200'; }
#	    if ($val &  0x400){ $val = 'style0x400'; }
#	    if ($val &  0x800){ $val = 'style0x800'; }
#	    if ($val &  0x1000){ $val = 'style0x1000'; }
#	    if ($val &  0x2000){ $val = 'style0x2000'; }
#	    if ($val &  0x4000){ $val = 'style0x4000'; }
#	    if ($val &  0x8000){ $val = 'style0x8000'; }
#	}
#	if ($func eq 'align') {
#	    if ($val &   1 )  { $val = 'align1'; }
#	    if ($val &   2 )  { $val = 'align2'; }
#	    if ($val &   4 )  { $val = 'align4'; }
#	    if ($val &   8 )  { $val = 'align8'; }
#	    if ($val &  0x10 ){ $val = 'align0x10'; }
#	    if ($val &  0x20 ){ $val = 'align0x20'; }
#	    if ($val &  0x40 ){ $val = 'align0x40'; }
#	    if ($val &  0x80 ){ $val = 'align0x80'; }
#	    if ($val &  0x100){ $val = 'align0x100'; }
#	    if ($val &  0x200){ $val = 'align0x200'; }
#	    if ($val &  0x400){ $val = 'align0x400'; }
#	    if ($val &  0x800){ $val = 'align0x800'; }
#	    if ($val &  0x1000){ $val = 'align0x1000'; }
#	    if ($val &  0x2000){ $val = 'align0x2000'; }
#	    if ($val &  0x4000){ $val = 'align0x4000'; }
#	    if ($val &  0x8000){ $val = 'align0x8000'; }
#	}
	elsif ($func eq 'attr') {
	    if    ($val eq 'A' ){ $val = 'Alpha'; }
	    elsif ($val eq 'N' ){ $val = 'Numeric'; }
	    elsif ($val eq 'B' ){ $val = 'Logical'; }
	    elsif ($val eq 'D' ){ $val = 'Date'; }
	    elsif ($val eq 'T' ){ $val = 'Time'; }
	    elsif ($val eq 'M' ){ $val = 'Memo'; }
	    elsif ($val eq 'I' ){ $attr = 'Image'; }
	}

	elsif ($func eq 'editControl') {
		if    ($val eq 'S') { $val = 'Static';     }#verified Staticincludes  Text, Lines, Ellipses, Rectangles
		elsif ($val eq 'E') { $val = 'Field';      }#verified really called Edit
		elsif ($val eq 'P') { $val = 'Pushbutton'; }#verified
		elsif ($val eq 'T') { $val = 'Table';      }#verified  #expand table info!!
		elsif ($val eq 'C') { $val = 'CheckBox';   }#verified
		elsif ($val eq 'L') { $val = 'Slider';     }#verified
		elsif ($val eq 'O') { $val = 'OLE2'; }
		elsif ($val eq 'I') { $val = 'Image'; }
		elsif ($val eq 'H') { $val = 'RichEdit';   }#Ferenc Polgar
		elsif ($val eq 'M') { $val = 'HTMLFile';   }#Ferenc Polgar
		elsif ($val eq 'N') { $val = 'Line';   }#Ferenc Polgar
		elsif ($val eq 'X') { $val = 'ActiveX';   }#Ferenc Polgar
		elsif ($val eq 'R') { $val = 'Radio';      }#verified
	}
	elsif ($func eq 'mod') {#Access (6)
		if    ($val eq 'R') { $val = 'Read'; }
		elsif ($val eq 'W') { $val = 'Write'; }
		elsif ($val eq 'A') { $val = 'Append'; }
		elsif ($val eq 'D') { $val = 'Direct'; }
	}
	elsif ($func eq 'read') {#Open Mode (8)
		if    ($val eq 'N') { $val = 'Normal'; }
		elsif ($val eq 'F') { $val = 'Fast'; }
		elsif ($val eq 'D') { $val = 'Damaged'; }
		elsif ($val eq 'R') { $val = 'Reindex'; }
	}
	elsif ($func eq 'opn') {#Share mode (5)
		if    ($val eq 'R') { $val = 'Read'; }
		elsif ($val eq 'W') { $val = 'Write'; }
		elsif ($val eq 'N') { $val = 'None'; }
	}
	elsif ($func eq 'endcheck') {
		if    ($val eq 'A') { $val = 'After'; }
		elsif ($val eq 'B') { $val = 'Before'; }
		elsif ($val eq 'I') { $val = 'Immediate'; }
	}
	elsif ($func eq 'ioformat') {
		if    ($val eq 'P') { $val = 'Page'; }
		elsif ($val eq 'L') { $val = 'Line'; }
		elsif ($val eq 'N') { $val = 'None'; }
	}
	elsif ($func eq 'iomedia') {
		if    ($val eq 'P') { $val = 'Printer'; }
		elsif ($val eq 'C') { $val = 'Console'; }
		elsif ($val eq 'S') { $val = 'Standard File'; }
		elsif ($val eq 'I') { $val = 'Internal File'; }
		elsif ($val eq 'U') { $val = 'User Driver'; }
	}
	elsif ($func eq 'eventscope') {
		if    ($val eq 'S') { $val = 'Subtree'; }
		elsif ($val eq 'T') { $val = 'Task'; }
	}
	elsif ($func eq 'eventcall') {
		if    ($val eq 'P') { $val = 'Program'; }
		elsif ($val eq 'T') { $val = 'Task'; }
	}
	$val;
}

sub	getPrgResources
{
	readin();
	die "expected RSRCE" if $_ !~ /^RSRCE/;


	while ( readin()) {
		if (/^DB/){
			$db++;
			($i) = $_ =~ /FILE=(\d+)/;
			$db[$db]->{idx} 	= $i;
			$db[$db]->{file} 	= 'None Defined';
			$db[$db]->{file} 	= expandYNexp($1) if  $_ =~ /EXP=(\d+),/;
			$db[$db]->{access}  = expandIOmode('mod', $1) if $_ =~ /MOD=(.)/;
			$db[$db]->{share}  	= expandIOmode('opn', $1) if $_ =~ /OPN=(.)/;
			$db[$db]->{'open'}  	= expandIOmode('read', $1) if $_ =~ /READ=(.)/;
			$db[$db]->{cache}= $1 if $_ =~ /SIZ=([0-9YN]+)/;  #601  can be number, Y or N
		}
		elsif (/^IO/){
			$io++;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{desc}   = $1 if $_ =~ /DESC="(.*?)",/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{'format'} = $1 if $_ =~ /FRM=(.)/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{media}  = $1 if $_ =~ /STRG=(.)/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{access} = $1 if $_ =~ /MOD=(.)/;
			$prgtaskName[$p]->{$hier}->{io}->[$io]->{file} = $exp[$p][$t][$1] if $_ =~ /EXP=(\d+),/;
		}
		elsif (/^EVNT=\{/) {
			$exp  = '';
			$scope='';
			$actv ='';
			$key  ='';
			$actvstr ='';#587
			$keystr  ='';#587
			$time ='';
			$mod ='' ;

			$actv  = $1 if /ACTV=(\d+)/;
			$key   = $1 if /KEY=(\d+)/;
			$time  = $1 if /TIME=(\d+)/;

			$scope = ($1 eq 'S')?'Subtask':'   Task' if /SCOPE=(.)/;
			$exp = $exp[$p][$t][$1] if /EXP=(\d+)/;

			$evnt[$evnt]->{key}= $key;
			$evnt[$evnt]->{actv}= $actv;
			$evnt[$evnt]->{keystr}= '';#587
			$evnt[$evnt]->{actvstr}= '';#587
			$evnt[$evnt]->{keystr}= $key_from_code{$key} if $key ne '';#587
			$evnt[$evnt]->{actvstr}= $action_from_code{$actv} if $actv ne '';#587
			$evnt[$evnt]->{'time'}= $time;
			$evnt[$evnt]->{'exp'}= $exp;

			$evnt[$evnt]->{scope} = $scope;

			readin();
			($mode, $task, $lock, $punct) = $_ =~ /MOD=(.),TSK=(\d+),LOCK=(.)(.)/;
			$evnt[$evnt]->{progTask}= ($mode eq 'T')?'   Task:':'Program:';

			$evnt[$evnt]->{progTaskNumber}= $task;
			$evnt[$evnt]->{lock}= $lock;
			if ($punct eq ',') {
				getArgsAndFlow();
				if (defined(@args))	{
					$i = 0;
					foreach $arg (@args){
						$evnt[$evnt]->{args}->[$i] = $arg;
						$i++;
					}
					undef(@args);
				}
			}
		    $evnt++;

		}
		elsif (/^DTLS/) {
			getDetails();
		}
		elsif (/^FLW=/) {
			doFlow();
		}
		elsif (/^DSP=/ ) {
			unshift @saved, $_ ;
			doDisplay();
		}
		elsif (/^FLD/) { #do nothing as it was all done in prescan
		}
		elsif (/^TSK=/) {
			initTaskMain();
			setHierarchicalPosition();
		}
		elsif (/^HDR=/) {
			$queryMode  = $1 if /QRY=(.),/;
			$modifyMode = $1 if /MDFY=(.),/;
			$deleteMode = $1 if /DEL=(.),/;
			$isResident = $1 if /RSDNT=(.),/;
		}
		elsif ($_ eq "PRG={\n" || /^DRPD/ ) { #dropdown menus
			unshift @saved, $_ ;
			last;
		}
	}
}
sub expandYNexp{
	my $x = shift;

	if ($x =~ /^(Y|N)$/){
		$x = $x eq 'N'?'No':'Yes';
	}
	elsif ($x =~ /(\d+)/) {
		if (defined($exp[$p][$t][$1])) {
			$x = $exp[$p][$t][$1];
		}
	}
	$x;
}
sub ynexp{
	my ( $field, $str) = @_;
	my $result = '?undefined?';

	if ($str =~ /=\{$field=(Y|N)/){
		$result = $1;
	}
	elsif ($str =~ /EXP=(\d+)/) {
		$result = $exp[$p][$t][$1];
	}
	$result;
}
sub extendYN{
	my $x = shift;

	if ($x =~ /^(Y|N)$/){
		$x = $x eq 'N'?'No':'Yes';
	}
	elsif ($x eq 'A') {
		$x = 'Ascending';
	}
	elsif ($x eq 'D') {
		$x = 'Descending';
	}
	$x;
}
format SORT_DETAIL =
  @>>  @>>>>>>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
	$v, $sortSeg[$v]->{'direction'}, $sortSeg[$v]->{'size'}, $sortSeg[$v]->{'field'}
.

#no sequence numbers   #601 add DB tag and reduce indent
format DB_DETAIL =
DB @>> @<<<<<<<<<<<<<<<<<<<<<<< @<<<<< @<<<< @<<<<<<< @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   $db[$v]->{idx}, $dd[$db[$v]->{idx}]{desc}, $db[$v]->{access},$db[$v]->{share},$db[$v]->{'open'}, $db[$v]->{cache}, $db[$v]->{file}
.
#format DB_DETAIL =
# @>>> @>>> @<<<<<<<<<<<<<<<<<<<<<<<  @<<<<<< @<<<<<<< @<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# $v, $db[$v]->{idx}, $dd[$db[$v]->{idx}]{desc}, $db[$v]->{access},$db[$v]->{share},$db[$v]->{'open'}, $db[$v]->{file}
#.
sub dumpEvents{
    my $i;

	return if (!defined(@evnt));
	print "\nEvents:\n\n";
	print "  Scope            Program/Task                        Key          Action                   Time    Expression\n";
	print "--------------------------------------------------------------------------------------------------------------------------------\n";

	foreach $i (@evnt) {
		$mode = $i->{progTask};
		$task = $i->{progTaskNumber};

		if ($i ->{progTask} =~ /^P/ ){
			$desc = "Call Prog: " . $prgtaskName[$task]->{'1'}->{desc};		#0573
		}
		else{
			$desc = "Call Task: " . $prgtaskName[$p]->{$hier . '.' . $task }->{desc}; #0573
		}

		$~ = 'EVENT_DETAIL';
		write;
		if (defined($i->{args}))	{
			$j = 1;
			foreach $arg (@{$i->{args}}){
				print "                  $j|$arg\n";
				$j++;
			}
		}
	}
	print "\n";

#0573,#574
format EVENT_DETAIL =
@>>>>>>  @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<  @<<<<<<<<<<<<<<<<<< @>>>>>>>>>> @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$i->{scope},  $desc,           $i->{keystr}, $i->{actvstr},$i->{'time'},$i->{'exp'}
.
}
sub dumpDBfiles{
	if (!defined($db[1])){
		return;
	}
	$v = 1;
	print "\n DB Files:\n";
	print "  +Fil+---- File Name ---------+Access+Share+--Open--+Cache+-Exp---+\n"; #601 re-align
	while( defined($db[$v] )){
		$~ = 'DB_DETAIL';
		write;
		$v++;
	}
}
sub dumpSortSegs{
	if (!defined($sortSeg[1])){
		return;
	}
	$v = 1;
	print "\n Sort Segments:\n";
	print "  +-#--Direction-Size-Field--\n";
	while( defined($sortSeg[$v] )){
		$~ = 'SORT_DETAIL';
		write;
		$v++;
	}
	$nSortSegs = 0;
	undef @sortSeg;
}
sub dumpVirtuals {
	my $firstChar;

	if (!defined($virt[$p][$t][1])){
		return;
	}
	$v = 1;
	print " Virtual Fields:\n";
	print "+-#-+---- Field Name --------+Typ+-Attr--------------+-- Picture --+------ Range -------+\n";
	while( defined($virt[$p][$t][$v] )){
		$~ = 'VIRTUAL_DETAIL';
		write;

#		printf( "% 4d %20s % 3d %7s %s\n",
#				$v,
#				$virt[$p][$t][$v]->{desc},
#				$virt[$p][$t][$v]->{type},
#				$virt[$p][$t][$v]->{attr},
#				$virt[$p][$t][$v]->{pic}
#			  );
		$v++;
	}
	#0606.01	dump again in tab separated format
	$v = 1;
	print "==Tab separated format for parameters:\n";
	print "#\tField Name\tTyp\tAttr\tPicture\tRange\tNotes\n"; #0607 knock off leading tab, add trailing tab and label for Notes
	while( defined($virt[$p][$t][$v]) ){
		$firstChar = substr( $virt[$p][$t][$v]->{desc},0,1);#0608 limit this dump to passed and returned values only
		if ( $firstChar eq 'p' ||  $firstChar eq 'r') { #0608
			printf( "%d\t%s\t%d\t%s\t%s\t\n", #0607 
					$v,
					$virt[$p][$t][$v]->{desc},
					$virt[$p][$t][$v]->{type},
					$virt[$p][$t][$v]->{attr},
					$virt[$p][$t][$v]->{pic}
				  );
		}
		$v++;
	}
}
sub getSortSegs
{
	$nSortSegs = 0;
	while (readin()) {
		if( /^SEG={FLD=(\d+),SIZ=(\d+),DIR=(.)/ ){
			$nSortSegs++;
			$sortSeg[ $nSortSegs ]->{'size'} = $2;
			$sortSeg[ $nSortSegs ]->{'direction'} = ($3 eq 'A')?'Ascending':'Descending';
			$sortSeg[ $nSortSegs ]->{'field'} = $var[$p]->{$hier}->{$1};
		}
		else {
			last;
		}
	}
	unshift @saved, $_;
}
sub	getDetails
{
	$mainFile = 0;
	$mainKey = 0;
	$keyExpression = 0; #0585
	$keyInfo = "0.";  #0585
	while (readin()) {
		if (/^KEY/) {
			$mainKey = $1 if $_ =~ /FLD=(\d)/;#does not appear if no main file
			$mainMod = $1 if $_ =~ /MOD=(.)/; #0585 sample of expression for key: KEY={MOD=N,EXP=1},
			$keyExpression = $1 if $_ =~ /EXP=(\d+)/; #0585
		}
		elsif (/^DB/) {
			$mainFile = $1 if $_ =~ /DB=(\d+)/;
			$mainFileDesc = $dd[$mainFile]->{desc};
		}
		elsif (/^SORT/) {
			getSortSegs();
		}
		elsif (/^FLW=(B|O),/) {
			($taskFlow,  $taskForceRecordDelete, $taskEndTaskCondition, $taskEndCheck ) = $_ =~ /FLW=(.),DEL=(\w+),END=(\w+),EMOD=(.),/;
			if ($taskForceRecordDelete =~ /\d+/) { $taskForceRecordDelete = $exp[$p][$t][$taskForceRecordDelete]; }
			if ($taskEndTaskCondition =~ /\d+/) { $taskEndTaskCondition = $exp[$p][$t][$taskEndTaskCondition]; }
			if ($taskFlow eq 'O' ) {
				$taskFlow = 'Online';
			}
			else {
				$taskFlow = 'Batch';
			}
		}
		elsif (/^MOD/) {
			$initialTaskMode = '?undefined?';
			if ($_ =~ /\{MOD=(.)/){
				$initialTaskMode = $initialTaskMode{$1};
			}
			elsif ($_ =~ /\{EXP=(\d+)/){
				$initialTaskMode = $exp[$p][$t][$1];
			}
		}
		elsif (/^LCT/) {
			$locateExp = 'None Defined';
			if ($_ =~ /\{EXP=(\d+)/){
				$locateExp = $exp[$p][$t][$1];
			}
			$locateDir = $1 if $_ =~ /DIR=(.)/;
			if    ($locateDir eq 'D' ) {$locateDir = 'Descending' ;}
			elsif ($locateDir eq 'A' ) {$locateDir = 'Ascending' ;}
		}
		elsif (/^RNG/) {
			$rangeExp = 'None Defined';
			if ($_ =~ /\{EXP=(\d+)/){
				$rangeExp = $exp[$p][$t][$1];
			}
			$rangeDir = $1 if  $_ =~ /DIR=(.)/;
			if    ($rangeDir eq 'D' ) {$rangeDir = 'Descending' ;}
			elsif ($rangeDir eq 'A' ) {$rangeDir = 'Ascending' ;}
		}
		elsif (/^FLG/) {
			$selectionTask 	= expandYNexp( $1 ) if $_ =~ /SLCT=(.+?),/;
			$confirmUpdate	= expandYNexp( $1 ) if $_ =~ /CNF=(.+?),/;
			$sloc  			= $1 if $_ =~ /SLOC=(.)/;
			$sfail   		= $1 if $_ =~ /SFAIL=(.)/;
			$lstrg   		= $1 if $_ =~ /LSTRG=(.)/;
			$forceRecordSuffix   		= $1 if $_ =~ /SUFIX=(.)/;


			if    ($sloc eq 'R' ) {$sloc = 'Retry' ;}
			elsif ($sloc eq 'A' ) {$sloc = 'Abort' ;}
			elsif ($sloc eq 'S' ) {$sloc = 'Skip'  ;}

			if    ($sfail eq 'R' ) {$sfail = 'Retry' ;}
			elsif ($sfail eq 'A' ) {$sfail = 'Abort' ;}
			elsif ($sfail eq 'S' ) {$sfail = 'Skip'  ;}

			if    ($lstrg eq 'I' ) {$lstrg = 'Immediate'; }
			elsif ($lstrg eq 'O' ) {$lstrg = 'On_Modify' ;}
			elsif ($lstrg eq 'A' ) {$lstrg = 'After_Modify' ;}
			elsif ($lstrg eq 'B' ) {$lstrg = 'Before_Update' ;}
			elsif ($lstrg eq 'M' ) {$lstrg = 'Minimum' ;}

		}
		elsif (/^WIN/) {
			($openTaskWindow, $closeTaskWindow, $foregroundWindow, $flip) = $_ =~ /OPN=(.+?),CLS=(.+?),FGND=(.+?),FLIP=(.)/;
		}
		elsif (/^DTLS/) {
			$refreshWindow = $1 if $_ =~ /DTLS=\{RTRN=(.)/;
		}
		elsif (/^BOX/) {
		}
		elsif (/^UPD/) {
			($updateDate, $updateTime) = $_ =~ /UPD=\{DATE="(.+?)",TIME="(.+?)"/;
		}
		elsif (/^SIDE_WIN=\{/) {
			$allowOptions = 'Yes';
			$allowQuery = 'Yes';
			$allowModify = 'Yes';
			$allowCreate = 'Yes';
			$allowDelete = 'Yes';
			$allowLocate = 'Yes';
			$allowRange = 'Yes';
			$allowKeyChange = 'Yes';
			$allowSorting = 'Yes';
			$allowIOFiles = 'Yes';
			$allowCycleRecordMain = 'Yes';
			$allowReports = 'Yes';
			$allowAbort = 'Yes';
			$allowKeyOpt = 'Yes';
			$allowLocateInQuery = 'Yes';
			while (readin()) {
				if (/^WIN=\{/) {
					unshift @saved, $_ ;
					last;
				}
				else {
					$allowOptions = $1 if $_ =~ /SIDE_WIN=(N|Y)/;
					$allowQuery =   ynexp( "QRY", $_) if /^QRY/;
					$allowModify =  ynexp( "MDFY", $_ ) if /^MDFY/;
					$allowCreate =  ynexp( "CRT", $_ ) if /^CRT/;
					$allowDelete =  ynexp( "DEL", $_ ) if /^DEL/;
					$allowLocate =  ynexp( "LCT", $_ ) if /^LCT/;
					$allowRange =   ynexp( "RNG", $_ ) if /^RNG/;
					$allowKeyChange = ynexp( "KEY", $_ ) if /^KEY/;
					$allowSorting = ynexp( "SORT", $_ ) if /^SORT/;
					$allowIOFiles = ynexp( "FILE", $_ ) if /^FILE/;
					$allowCycleRecordMain = ynexp( "CYCL", $_ ) if /^CYCL/;
					$allowReports = ynexp( "RPR", $_ ) if /^RPR/;
					$allowAbort =   ynexp( "ABRT", $_ ) if /^ABRT/;
					$allowKeyOpt =  ynexp( "KOPT", $_ ) if /^KOPT/;
					$allowLocateInQuery = ynexp( "QLCT", $_ ) if /^QLCT/;
				}
			}
		}

		elsif (/^FLW=\{/) {
			$selectionTask        = extendYN( $selectionTask );
			$isResident 	      = extendYN($isResident);
			$openTaskWindow       = expandYNexp($openTaskWindow);
			$closeTaskWindow      = expandYNexp($closeTaskWindow);
			$foregroundWindow     = expandYNexp($foregroundWindow);
			$refreshWindow        = expandYNexp($refreshWindow);
			$flip                 = expandYNexp($flip);
			$allowCycleRecordMain = expandYNexp($allowCycleRecordMain);
			$confirmUpdate        = expandYNexp($confirmUpdate);
			$locateExp            = extendYN($locateExp);#already expanded to expression
			$rangeExp             = extendYN($rangeExp);#already expanded to expression
			$taskEndTaskCondition = extendYN($taskEndTaskCondition);#already expanded to expression
			$taskEndCheck = expandIOmode( 'endcheck', $taskEndCheck);
			$forceRecordSuffix = expandYNexp($forceRecordSuffix);#581
			$taskForceRecordDelete  = expandYNexp($taskForceRecordDelete);
			$allowOptions = extendYN($allowOptions);
			$allowModify = extendYN($allowModify);
			$allowCreate = extendYN($allowCreate);
			$allowDelete = extendYN($allowDelete);
			$allowQuery = extendYN($allowQuery);
			$allowLocate = extendYN($allowLocate);
			$allowRange = extendYN($allowRange);
			$allowKeyChange = extendYN($allowKeyChange);
			$allowSorting = extendYN($allowSorting);
			$allowIOFiles = extendYN($allowIOFiles);
			$allowAbort = extendYN($allowAbort);
			$allowKeyOpt = extendYN($allowKeyOpt);
			$allowLocateInQuery = extendYN($allowLocateInQuery);
			$allowReports = extendYN($allowReports);

			$taskName = ($hier eq '1')?$progName:$prgtaskName[$p]->{$hier}->{desc};
			if ($compatibilityMode) {
				print "\n !Last Update: $updateDate $updateTime\n\n";
 				print "Task Name: $taskName\n";
			}
			else {
 				print "\n\001\nTask Name: $taskName \tLast Update: $updateDate $updateTime\n";#583
			}
			if ($mainFile == 0 ) {
				$fileDesc = '';
				$keyDesc = '';
			}
			else {
				$fileDesc = $dd[$mainFile]->{desc};
				if ($mainKey == 0 ) {
					$keyDesc = '';
					if( $keyExpression ne 0 ){	#0585
						$keyInfo = "Expr: " . $exp[$p][$t][$keyExpression];	#0585
					}
				}
				else {
					$keyDesc = $dd[$mainFile]->{key}->[$mainKey];
					$keyInfo = "$mainKey. $keyDesc";  #0585
				}
			}
			print <<"TASKTOP";
--------------------------------------------------
                Main File: $mainFile  $fileDesc   Key: $keyInfo
TASKTOP

print "                Task Type: $taskFlow\n" if $taskFlow ne $ini{lc('deftaskFlow')};
print "             Initial Mode: $initialTaskMode\n" if $initialTaskMode ne $ini{lc('defInitialTaskMode')};
print "          Selection Table: $selectionTask\n" if $selectionTask ne $ini{lc('defselectionTask')};
print "            Resident Task: $isResident\n" if $isResident ne $ini{lc('defisResident')};

# //Task Control

print "         Open Task Window: $openTaskWindow\n" if $openTaskWindow ne $ini{lc('defopenTaskWindow')};
print "        Close Task Window: $closeTaskWindow\n" if $closeTaskWindow ne $ini{lc('defcloseTaskWindow')};
print "        Foreground Window: $foregroundWindow\n" if $foregroundWindow ne $ini{lc('defforegroundWindow')};
print "      Refresh Task Window: $refreshWindow\n" if $refreshWindow ne $ini{lc('defrefreshWindow')};

print "      Flip Field on Input: $flip\n" if $flip ne $ini{lc('defflip')};
print "        Cycle Record Main: $allowCycleRecordMain\n" if $allowCycleRecordMain ne $ini{lc('defallowCycleRecordMain')};
print "           Confirm Update: $confirmUpdate\n" if $confirmUpdate ne $ini{lc('defconfirmUpdate')};
print "             Form Records: 0\n" if $formRecords ne $ini{lc('def0')};

print "               Locate Exp: $locateExp\n" if $locateExp ne $ini{lc('deflocateExp')};
print "             Locate Order: $locateDir\n" if $locateDir ne $ini{lc('deflocateDir')};

print "                Range Exp: $rangeExp\n" if $rangeExp ne $ini{lc('defrangeExp')};
print "              Range Order: $rangeDir\n" if $rangeDir ne $ini{lc('defrangeDir')};
print "                 End Task: $taskEndTaskCondition\n" if $taskEndTaskCondition ne $ini{lc('deftaskEndTaskCondition')};
print "                End Check: $taskEndCheck\n" if $taskEndCheck ne $ini{lc('deftaskEndCheck')};
print "      Force Record Suffix: $forceRecordSuffix\n" if $forceRecordSuffix ne $ini{lc('defForceRecordSuffix')};
print "      Force Record Delete: $taskForceRecordDelete\n" if $taskForceRecordDelete ne $ini{lc('deftaskForceRecordDelete')};

print "         Locking Strategy: $lstrg\n" if $lstrg ne $ini{lc('deflstrg')};
print "         On Locked Record: $sloc\n" if $sloc ne $ini{lc('defsloc')};
print "  On Failed Record Access: $sfail\n" if $sfail ne $ini{lc('defsfail')};

print "            Allow Options: $allowOptions\n"    if $allowOptions   ne $ini{lc('defallowOptions')}; #577
print "             Allow Modify: $allowModify\n"     if $allowModify    ne $ini{lc('defAllowModify')};
print "             Allow Create: $allowCreate\n"     if $allowCreate    ne $ini{lc('defAllowCreate')};
print "             Allow Delete: $allowDelete\n" 	  if $allowDelete    ne $ini{lc('defAllowDelete')};
print "              Allow Query: $allowQuery\n" 	  if $allowQuery     ne $ini{lc('defAllowQuery')};
print "             Allow Locate: $allowLocate\n" 	  if $allowLocate    ne $ini{lc('defAllowLocate')};
print "              Allow Range: $allowRange\n"      if $allowRange     ne $ini{lc('defAllowRange')};
print "         Allow Key Change: $allowKeyChange\n"  if $allowKeyChange ne $ini{lc('defAllowKeyChange')};
print "            Allow Sorting: $allowSorting\n"    if $allowSorting   ne $ini{lc('defAllowSorting')};
print "          Allow I/O Files: $allowIOFiles\n"    if $allowIOFiles   ne $ini{lc('defAllowIOFiles')};
print "              Allow Abort: $allowAbort\n"      if $allowAbort     ne $ini{lc('defAllowAbort')};
print "   Allow Key Optimization: $allowKeyOpt\n"     if $allowKeyOpt    ne $ini{lc('defAllowKeyOpt')};
print "    Allow Locate in Query: $allowLocateInQuery\n" if $allowLocateInQuery ne $ini{lc('defAllowLocateInQuery')};
print "            Allow Reports: $allowReports\n" if $allowReports ne $ini{lc('defAllowReports')};


            if ($hier eq '1'){
print "              Query Right: $queryRight\n" if $queryRight ne $ini{lc('defqueryRight')};
print "             Modify Right: $modifyRight\n" if $modifyRight ne $ini{lc('defmodifyRight')};
print "           Deletion Right: $deleteRight\n" if $deleteRight ne $ini{lc('defdeleteRight')};
print "          Execution Right: $executeRight\n" if $executeRight ne $ini{lc('defexecuteRight')};


				printTaskHierarchy($p);
			}
			print "//Task Levels\n\n";


			dumpVirtuals();
			dumpEvents();
			dumpDBfiles();
			dumpSortSegs();
	        unshift @saved, $_;
			last;
		}
	}
}
sub initTaskMain{
	$t++;
	$evnt = 0;
	undef @evnt;
	$io = 0;
	$db = 0;
	undef @db;
	$nSortSegs = 0;
	undef @sortSeg;
}
sub writeProgram
{
	$p++;
	$t=0;
	initTaskMain();
	$hier='1';
	$mainFile = 'None';

	readin();

	die "expected HDR" if $_ !~ /^HDR/;

	$progName = '--';  #There won't be a DESC token if there is no text #v055
	$progName = $1 if /DESC="(.+?)"/;
	print STDOUT ".... $p. $progName\n" if $opt_v;
	$queryRight   = 'Not_Defined';
	$modifyRight  = 'Not_Defined';
	$deleteRight  = 'Not_Defined';
	$executeRight = 'Not_Defined';

	$queryRight   = rights($1) if /QRY=(\d+)/;
	$modifyRight  = rights($1) if /MDFY=(\d+)/;
	$deleteRight  = rights($1) if /DEL=(\d+)/;
	$executeRight = rights($1) if /EXE=(\d+)/;

	$isResident = $1 if /RSDNT=(.),/;

	# replace characters prohibited in file names with hyphens so epsilon can write a file name
	# replace spaces so epsilon is not confused when creating buffer names
	$progAsFname = $progName;#600
    # I tried to retain spaces in filenames  but wasn't successful.
	# even if successful, wouldn't Epsilon get confused with buffer names?
	$progAsFname =~ tr/\\\/?*:<>% /-/;
#   $progAsFname =~ tr/\\\/?*:<>%/-/; #0608 don't replace the spaces as I had been doing.
	$prgNumber = $opt_n?(sprintf("%04d",$p)):'';#600
	
	if( $ini{lc('generateHtml')} eq 'True' ){$FileExt = 'html'}#584
	else {$FileExt = 'txt'} #610 FileExt was ezr, but set to txt so Google will index it.
	$outfile = "z$prgNumber-$progAsFname." . $FileExt;

	print HTMLMAIN "<tr><td><a href=\"$outfile\"> $prgNumber </a><td><a href=\"$outfile\"> $progName </a>\n";#600

	open( OUT, "> $outfile" );
#   open( OUT, "> \"$outfile\"" ); #0608 put quotes around the filename because it will have spaces - Doesn't work anyway
	select OUT;
	$startSecs = time;
	
	if ($os eq 'Windows_NT'){
#print "getting date and time\n";
		$date = `date /t`;
		$time = `time /t`;
#print "done getting date and time\n";
		chomp( $date );
		chomp( $time );
		$date .= ' ' . $time;
	}
	else{
		$date = 'n/a';
#		$date = `date`;
	}
	if( $ini{lc('generateHtml')} eq 'True' ){ #584
		print "<html><title></title><body><pre>\n";
	}
	print "mgFargo: Magic Source Translation - Version $mgMajorVers.$mgMinorVers $versionDate by Ira Gershenhorn w\\Perl $] \n\n" ;
	print " Program: $progName \t\t$date\n\n" ;

	$indentLevel = 1;
	$indentLevelPrev = 1;
	@indentExp =();
	getPrgResources();
	$elapsed = time - $startSecs;
	print "\n ***Elapsed Time for $progName: $elapsed seconds\n\n";
	undef $exp[$p];
	if( $ini{lc('generateHtml')} eq 'True' ){#584
		print "</pre></body></html>\n";
	}
	close OUT;
}
sub	getArgsAndFlow {
	$orig = $_;
	undef @args;
	while (1){
		readin();
		if ( $magicVersion <= 799 && /^EXP=(\d+)/ ||	#578
			 $magicVersion >= 800 && /^ARG=\{EXP=(\d+)/ 
		   ){
			my $tmp = $exp[$p][$t][$1];
			if ($tmp =~ /\'([A-Z]+)\'VAR/) {
				$tmp = '@' . varDesc($1);
			}
			push @args, $tmp;
		}
		elsif ( $magicVersion <= 799 && /^ARG="(\w+)"/ || #578
			 $magicVersion >= 800 && /ARG=\{VAR="(\w+)"/
		   ){
			push @args, varDesc($1);
		}
		else{
			unshift @saved, $_;
			last;
		}
		if (/FLW=\{/){
			chomp($orig);
			$_ = $orig . $_;
			last;
		}
	}
}
#no sequence numbers #0604
format VIRTUAL_DETAIL =
       @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @>>> @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    	$virt[$p][$t][$v]->{desc},	$virt[$p][$t][$v]->{type}, $virt[$p][$t][$v]->{attr}, $virt[$p][$t][$v]->{pic}, $virt[$p][$t][$v]->{range}
.

# format VIRTUAL_DETAIL =
# @>>>> @<<<<<<<<<<<<<<<<<<<< @>>> @<<<<<<< @<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
# $v,	$virt[$p][$t][$v]->{desc},	$virt[$p][$t][$v]->{type}, $virt[$p][$t][$v]->{attr}, $virt[$p][$t][$v]->{pic}, $virt[$p][$t][$v]->{range}
#.

sub readPrgList{
    my $file = shift;
    my $p = 1;

	print STDOUT "opening $file for program list\n";
    open ( PRG, "< $file ");
    while (<PRG>){
		if (/\d+:\d+/){
			s/^\0x0c//;
			$_ =~ /^(.+)\d\d\/\d\d\//;
			$prgtaskName[$p]->{'1'}->{desc} = $1;
			$p++;
		}
    }
    close PRG;
}
sub printSubTree{
	my ($pp, $phier) = @_;

	$phier .= '.1';
	while ( defined(	$prgtaskName[$pp]->{$phier}->{desc})){
		$phierLessOne = substr($phier,1,10);
		$dots = $phier =~ tr/\./\./;#count em
		print  substr( $tabstr, 0, $dots+1), "$prgtaskName[$pp]->{$phier}->{desc}\t$phierLessOne\n";#600
		printSubTree($pp, $phier);
		$phier =~ s/(\d+)$/$1+1/e;  #Try the next one
	}
}
sub printTaskHierarchy {
	my $pp = shift;

	if (defined($prgtaskName[$pp]->{'1.1'}->{desc})){
		print "\nTask Hierarchy:";
		print "\n------------------------------------------------------------";#600
		print "\n\t$progName\n";

		printSubTree($pp, '1');
		print "------------------------------------------------------------\n";#600 
	}
}


sub usage{
   pod2usage( { -message => "\n" . $0 . ": ". $error . "\n\n" . $copyrightLine ,
				-exitval => 1  ,  
				-input => "mgFargo.pod",
				-verbose => 0  
				 } );
}
sub detailedUsage{
   pod2usage( { -message => $copyrightLine ,
				-exitval => 0  ,  
				-verbose => 1,
				-input => "mgFargo.pod",
				-output => \*STDOUT
				 } );
}
sub manpage{
   pod2usage( { -message => $copyrightLine ,
				-exitval => 0  ,  
				-verbose => 2,
				-input => "mgFargo.pod",
				-output => \*STDOUT
				 } );
}
sub read_mgFargo_ini{
	my $path = $1 if $file =~ /(^.*\/)/;
	my $ini = $path . 'mgFargo.ini';
	$ini = $opt_i; #588
	print STDOUT "testing for mgFargo.ini at [$opt_i]\n";#588
	if (-f $ini){
		my $skipping = 0;

		print STDOUT "opening $ini configuration parameters\n";
		open INI, "< $ini";
		while (<INI>) {
			
			if (!$skipping && /^(\w+)\s*=\s*([^\s;]+)/)	{
				$ini{lc($1)}=$2;
			}
			elsif ( /^\[(\w+)\]/){
				if ( $ini{lc('enableDefaults')} ne 'True' ){
					last;
				}
				elsif (	!/^\[$ini{lc('defaultsSection')}\]/i){
					$skipping = 1;
				}
			}
		}
		close INI;
	}
	else { print STDOUT "Warning: mgFargo.ini not found!\n";}#588

}
#Typical line
# 0         1         2         3
# 01234567890123456789012345678901234567890
#User Action 1      =           ,  219,    0,0x000000000
sub read_act_eng{ #587
	my $act_eng_path = $1 if $file =~ /(^.*\/)/;
	my $act_eng = $act_eng_path . 'act_std.eng';
	print STDOUT "testing for act_std.eng\n";
	if (-f $act_eng){

		print STDOUT "opening $act_eng Actions Definition\n";
		open INI, "< $act_eng";
		while (<INI>) {
			$actcode = substr($_, 34,3);
			$actcode =~ s/ *([^ ]+)/$1/; #There's gotta be a cleaner way to strip leading space.
			$actstring = substr($_,0,18);

			$code_from_act{$actstring}= $actcode;
			$action_from_code{$actcode}=$actstring;

			$keycode = substr($_, 40,3);
			$keycode =~ s/ *([^ ]+)/$1/; #There's gotta be a cleaner way to strip leading space.
			$keystring = substr($_,21,10);

			$code_from_key{$keystring}= $keycode;
			$key_from_code{$keycode}=$keystring;
		}
		close INI;
	}
}
#600
#Typical line
# 0         1         2         3
# 01234567890123456789012345678901234567890
#Default Table Edit Field,MS Sans Serif,8,0,0
sub read_fnt_eng{ #600
	my $fnt_eng_path = $1 if $file =~ /(^.*\/)/;
	my $fnt_eng = $fnt_eng_path . 'fnt_std.eng';
	my $fnt_index = 0;
	print STDOUT "testing for fnt_std.eng\n";
	if (-f $fnt_eng){

		print STDOUT "opening $fnt_eng Font Definition\n";
		open INI, "< $fnt_eng";
		while (<INI>) {
			chomp;
			$fnt_index+=1;
			($fnt_use, $fnt_face,$fnt_size,$fnt_number,$fnt_style) = split( /,/ );
			$fnt[$fnt_index]->{use} = $fnt_use;
			$fnt[$fnt_index]->{face} = $fnt_face;
			$fnt[$fnt_index]->{size} = $fnt_size;
			$fnt[$fnt_index]->{number} = $fnt_number;
			$fnt[$fnt_index]->{style} = $fnt_style;
		}
		close INI;
	}
}

sub makeFontString {
	$fontString = "Font:$frm_fnt,$fnt[$frm_fnt]->{use}~$fnt[$frm_fnt]->{face}~$fnt[$frm_fnt]->{size}~$fnt[$frm_fnt]->{style}";
}
sub printFormItem{
	if( $printFormItem){
		$printFormItem=0;
		write;
		undef($text );
		undef($itm_txt );
		undef($exp_txt );
		undef($row );
		undef($col );
		undef($rows );
		undef($cols );
		undef($attr );
		undef($color );
	}

}